From 9840c1d2e5561b29a84dd0e0bcd0ad01f6b01244 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 28 Jan 2026 23:57:57 +0100 Subject: [PATCH 01/12] refactor(tox): split static checks into individual environments Split the monolithic [testenv:static] into individual check environments for finer-grained control and parallel execution: - spellcheck: codespell. - lint: ruff check. - format: ruff format --check. - typecheck: mypy. - spec-lint: ethereum-spec-lint. - lockcheck: uv lock --check. - actionlint: GitHub Actions workflow linting. Add fast-checks aggregate alias and keep static for backwards compat. Ref: ethereum/execution-specs#2041 --- tox.ini | 69 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/tox.ini b/tox.ini index 22b12f61212..ceef9663c5b 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,6 @@ envlist = py3 pypy3 json_infra - static optimized tests_pytest_py3 tests_pytest_pypy3 @@ -17,24 +16,72 @@ envlist = benchmark-fixed-opcode-config spec-docs mkdocs - changelog + # Fast static checks (individual) + spellcheck + lint + format + typecheck + spec-lint + lockcheck + actionlint markdownlint + changelog + # Aggregate aliases + fast-checks + static [testenv] runner = uv-venv-lock-runner uv_seed = false wheel_build_env = .pkg -[testenv:static] -description = Run spelling, lint, typechecking and dependency checks +# Individual static check environments +[testenv:spellcheck] +description = Run spelling check using codespell +commands = codespell + +[testenv:lint] +description = Run linting checks using ruff +commands = ruff check + +[testenv:format] +description = Run code formatting checks using ruff +commands = ruff format --check + +[testenv:typecheck] +description = Run type checking using mypy +commands = mypy + +[testenv:spec-lint] +description = Run Ethereum specification custom lints +commands = ethereum-spec-lint + +[testenv:lockcheck] +description = Verify uv.lock is in sync with pyproject.toml +commands = uv lock --check + +[testenv:actionlint] +description = Run linting on GitHub Actions workflow files +commands = actionlint -pyflakes pyflakes -shellcheck "shellcheck -S warning" + +# Aggregate alias - runs all fast static checks in sequence +[testenv:fast-checks] +description = Run all fast static checks (spelling, lint, format, typecheck, spec-lint, lock, actions, markdown, changelog) commands = - codespell - ruff check - ruff format --check - mypy - ethereum-spec-lint - uv lock --check - actionlint -pyflakes pyflakes -shellcheck "shellcheck -S warning" + {[testenv:spellcheck]commands} + {[testenv:lint]commands} + {[testenv:format]commands} + {[testenv:typecheck]commands} + {[testenv:spec-lint]commands} + {[testenv:lockcheck]commands} + {[testenv:actionlint]commands} + {[testenv:markdownlint]commands} + {[testenv:changelog]commands} + +# Backwards compatibility alias +[testenv:static] +description = Run all static checks (alias for fast-checks) +commands = {[testenv:fast-checks]commands} [testenv:tests_pytest_py3] description = Run the testing package unit tests (with Python) From 3361a3346b0ef8764cb6515bfbdd7754a1b0f21a Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 00:45:34 +0100 Subject: [PATCH 02/12] feat(tox): add fix hints for static checks Add scripts/fast_checks.py that wraps each static check with actionable fix hints on failure: - Prints clear "Check failed" header with tool name. - Shows how to auto-fix (where applicable). - Shows verify command. - Writes to GITHUB_STEP_SUMMARY in CI for job summaries. Update tox environments to use the wrapper script. Ref: ethereum/execution-specs#2041 --- docs/dev/test_actions_locally.md | 55 +-- docs/getting_started/code_standards.md | 10 +- .../getting_started/code_standards_details.md | 20 +- scripts/fast_checks.py | 330 ++++++++++++++++++ tox.ini | 32 +- 5 files changed, 400 insertions(+), 47 deletions(-) create mode 100644 scripts/fast_checks.py diff --git a/docs/dev/test_actions_locally.md b/docs/dev/test_actions_locally.md index 4653c9b9392..e5fe9fee340 100644 --- a/docs/dev/test_actions_locally.md +++ b/docs/dev/test_actions_locally.md @@ -44,23 +44,18 @@ will output something similar to: ```bash INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock' -Stage Job ID Job name Workflow name Workflow file Events -0 evmone-coverage-diff evmone-coverage-diff Evmone Coverage Report coverage.yaml pull_request -0 deploy deploy Deploy Docs Main docs_main.yaml push -0 deploy deploy Deploy Docs Tags docs_tags.yaml push -0 features features Build and Package Fixtures fixtures.yaml push,workflow_dispatch -0 feature-names feature-names Build and Package Fixtures for a feature fixtures_feature.yaml push,workflow_dispatch -0 lint Lint python sources with ruff Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 typecheck Typecheck python sources with mypy Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 spellcheck Spellcheck sources with pyspelling Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 markdownlint Lint markdown files with markdownlint Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 mkdocs Build html documentation with mkdocs Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 pytest_framework Run unit tests, ${{ matrix.os }}, ${{ matrix.python }} Tox tox_verify.yaml push,pull_request,workflow_dispatch -0 tests_deployed Fill tests, deployed, ${{ matrix.os }}, ${{ matrix.python }} Tox tox_verify.yaml push,pull_request,workflow_dispatch -1 build build Build and Package Fixtures fixtures.yaml push,workflow_dispatch -1 build build Build and Package Fixtures for a feature fixtures_feature.yaml push,workflow_dispatch -2 release release Build and Package Fixtures fixtures.yaml push,workflow_dispatch -2 release release Build and Package Fixtures for a feature fixtures_feature.yaml push,workflow_dispatch +Stage Job ID Job name Workflow name Workflow file Events +0 checks Spellcheck Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Format Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Typecheck Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Spec Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Lock Check Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Action Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Changelog Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 markdownlint Markdown Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 sha-pinned-actions SHA Pinned Actions Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +... ``` The `Job ID` is required to run a specific workflow and is provided to the `-j` option of `gh act`. @@ -77,15 +72,15 @@ DEFAULT_PYTHON_VERSION=3.12 and use the `--var-file` option to specify the file: ```bash -gh act --workflows .github/workflows/tox_verify.yaml -s GITHUB_TOKEN=$(gh auth token) --var-file=gh_vars.txt -j lint +gh act --workflows .github/workflows/fast-checks.yaml --var-file=gh_vars.txt ``` ### Running Workflows that use a Matrix Strategy -This is optional, recent versions will automatically detect the matrix strategy and run supported values. To run a specific matrix value, use the `--matrix` option: +This is optional, recent versions will automatically detect the matrix strategy and run supported values. To run a specific matrix item, use the `--matrix` option: ```bash -gh act --workflows .github/workflows/tox_verify.yaml -s GITHUB_TOKEN=$(gh auth token) --matrix python:3.12 -j pytest_framework +gh act --workflows .github/workflows/fast-checks.yaml --var-file=gh_vars.txt --matrix name:"Python Lint" ``` ### Running Release Workflows @@ -103,7 +98,7 @@ Release builds require the `ref` input to be specified. To test a release build 2. Run `act` and specify the workflow file, the Github token, and the event file: ```bash - gh act -j build --workflows .github/workflows/fixtures_feature.yaml -s GITHUB_TOKEN=$(gh auth token) -e event.json + gh act -j build --workflows .github/workflows/release_fixture_feature.yaml -s GITHUB_TOKEN=$(gh auth token) -e event.json ``` ### Manually Specifying the Docker Image @@ -115,3 +110,21 @@ It's possible to specify the Docker image used by the `act` tool for a specific ``` This can be added to any `gh act` command. + +### Fixing Permission Errors with Tool Cache + +When running workflows that use `setup-uv` or similar setup actions, you may encounter permission errors like: + +```text +::error::EACCES: permission denied, mkdir '/opt/hostedtoolcache/uv/0.9.27' +``` + +This happens because the container user doesn't have write access to `/opt/hostedtoolcache/`. Fix this by redirecting the tool cache to a writable location: + +```bash +gh act --workflows .github/workflows/fast-checks.yaml \ + -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest \ + --env RUNNER_TOOL_CACHE=/tmp/tool_cache +``` + +The `RUNNER_TOOL_CACHE` environment variable tells setup actions where to install tools, avoiding the permission issue without requiring root access. diff --git a/docs/getting_started/code_standards.md b/docs/getting_started/code_standards.md index f52e99d7c43..e39a8373997 100644 --- a/docs/getting_started/code_standards.md +++ b/docs/getting_started/code_standards.md @@ -1,18 +1,18 @@ # Code Standards -This document outlines the coding standards and practices used in the @ethereum/execution-spec-tests repository. +This document outlines the coding standards and practices used in the @ethereum/execution-specs repository. ## Code and CI Requirements -Code pushed to @ethereum/execution-spec-tests must fulfill the following checks in [CI](https://github.com/ethereum/execution-spec-tests/actions/workflows/tox_verify.yaml): +Code pushed to @ethereum/execution-specs must fulfill the following checks in [CI](https://github.com/ethereum/execution-specs/actions/workflows/fast-checks.yaml): | Type | Tox Command | Explanation | | ---------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | Lint & code formatting | `uvx tox -e lint` | Python lint, format and module import check via `ruff` | | Typecheck | `uvx tox -e typecheck` | Objects that provide typehints pass type-checking via `mypy`. | -| Framework unit tests | `uvx tox -e pytest` | All framework unit tests must execute correctly. | -| EL Client test cases | `uvx tox -e tests-deployed` | All client test cases for deployed forks can be generated. | -| Benchmark EL Test cases | `uvx tox -e tests-deployed-benchmark` | All client test cases specific to benchmarks for deployed forks can be generated. | +| Framework unit tests | `uvx tox -e tests_pytest_py3` | All framework unit tests must execute correctly. | +| Fill tests | `uvx tox -e py3` | All test cases for deployed forks can be generated. | +| Benchmark tests | `uvx tox -e benchmark-gas-values` | Benchmark test cases can be generated. | | HTML doc build | `uvx tox -e mkdocs` | Documentation generated without warnings. | | Spellcheck | `uvx tox -e spellcheck` | Code and documentation spell-check using codespell. | | Markdown lint | `uvx tox -e markdownlint` | Markdown lint (requires [additional dependency](code_standards_details.md#additional-dependencies)). | diff --git a/docs/getting_started/code_standards_details.md b/docs/getting_started/code_standards_details.md index c21588d0906..a68f973fe3b 100644 --- a/docs/getting_started/code_standards_details.md +++ b/docs/getting_started/code_standards_details.md @@ -1,6 +1,6 @@ # Detailed Code Standards -This page provides in-depth information about the code standards and verification processes in @ethereum/execution-spec-tests. +This page provides in-depth information about the code standards and verification processes in @ethereum/execution-specs. ## Running Tox Environments @@ -24,6 +24,16 @@ List all available environments: uvx tox -av ``` +### Fast Checks + +Run all fast static checks before pushing (recommended): + +```console +uvx tox -e fast-checks +``` + +This runs lint, format, typecheck, spellcheck, spec-lint, lockcheck, actionlint, markdownlint, and changelog validation in sequence. On failure, each check provides a **fix hint** explaining how to resolve the issue. + ### Specific Environment Commands Run specific environments using the `-e` flag: @@ -35,19 +45,19 @@ uvx tox -e lint,typecheck,spellcheck #### For Test Case Changes (`./tests/`) ```console -uvx tox -e lint,typecheck,spellcheck,tests-deployed +uvx tox -e fast-checks,py3 ``` #### For Framework and Library Changes (`./src/`) ```console -uvx tox -e lint,typecheck,spellcheck,pytest +uvx tox -e fast-checks,tests_pytest_py3 ``` #### For Documentation Changes (`./docs/`) ```console -uvx tox -e spellcheck,markdownlint,mkdocs,changelog +uvx tox -e fast-checks,mkdocs ``` !!! note "Tox Virtual Environment" @@ -93,7 +103,7 @@ For more information, see [Pre-commit Hooks Documentation](../dev/precommit.md). ## Formatting and Line Length -The Python code in @ethereum/execution-spec-tests is formatted with `ruff` with a line length of 100 characters. +The Python code in @ethereum/execution-specs is formatted with `ruff` with a line length of 100 characters. ### Ignoring Bulk Change Commits diff --git a/scripts/fast_checks.py b/scripts/fast_checks.py new file mode 100644 index 00000000000..230311785fa --- /dev/null +++ b/scripts/fast_checks.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python3 +""" +Fast checks runner with fix hints. + +Run static checks with actionable fix hints on failure. +Users run checks via tox; this script provides the implementation with +helpful error messages and GitHub Actions integration. + +Usage: + python scripts/fast_checks.py + +Available checks: + spellcheck, lint, format, typecheck, spec-lint, lockcheck, + actionlint, markdownlint, changelog +""" + +import argparse +import os +import re +import shutil +import subprocess +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Callable + + +@dataclass +class Check: + """Configuration for a single check.""" + + name: str + fix_hint: str + verify_cmd: str + run: Callable[[], int] # Function that runs the check, returns exit code + + +def write_github_summary(check: Check, check_key: str, output: str) -> None: + """Write failure summary to GITHUB_STEP_SUMMARY if in CI.""" + summary_file = os.environ.get("GITHUB_STEP_SUMMARY") + if not summary_file: + return + + # Truncate output if too long + max_output = 2000 + if len(output) > max_output: + output = output[:max_output] + "\n... (truncated)" + + with open(summary_file, "a") as f: + f.write(f"## āŒ {check.name} failed\n\n") + f.write("```\n") + f.write(output) + f.write("\n```\n\n") + f.write("### How to fix\n\n") + f.write("```bash\n") + f.write(check.fix_hint) + f.write("\n```\n\n") + f.write("### How to verify\n\n") + f.write("Run the tool directly:\n\n") + f.write("```bash\n") + f.write(check.verify_cmd) + f.write("\n```\n\n") + f.write("Or via tox:\n\n") + f.write("```bash\n") + f.write(f"tox -e {check_key}\n") + f.write("```\n") + + +def strip_markdown_code_blocks(text: str) -> str: + """Remove markdown code block markers for terminal output.""" + # Remove ```bash and ``` markers + return re.sub(r"```\w*\n?", "", text) + + +def print_fix_hint(check: Check) -> None: + """Print fix hint to stderr.""" + sep = "=" * 60 + hint = strip_markdown_code_blocks(check.fix_hint).strip() + print(f"\n{sep}", file=sys.stderr) + print(f"{check.name} failed:", file=sys.stderr) + print(sep, file=sys.stderr) + print(hint, file=sys.stderr) + print(f"\nVerify fix:\n{check.verify_cmd}", file=sys.stderr) + print(sep, file=sys.stderr) + + +def run_command(cmd: list[str]) -> tuple[int, str]: + """Run command, return exit code and combined output.""" + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.stdout: + print(result.stdout, end="") + if result.stderr: + print(result.stderr, end="", file=sys.stderr) + + return result.returncode, result.stdout + result.stderr + + +def find_project_root() -> Path: + """Locate the root directory of this project.""" + script_dir = Path(__file__).resolve().parent + for parent in [script_dir, *script_dir.parents]: + if (parent / "pyproject.toml").exists() and (parent / ".git").exists(): + return parent + + raise FileNotFoundError( + "Unable to locate project root! " + "Looking for a directory with both pyproject.toml and .git." + ) + + +# Check implementations + + +def run_codespell() -> int: + """Run codespell spelling check.""" + code, _ = run_command(["codespell"]) + return code + + +def run_ruff_check() -> int: + """Run ruff linting check.""" + code, _ = run_command(["ruff", "check"]) + return code + + +def run_ruff_format() -> int: + """Run ruff format check.""" + code, _ = run_command(["ruff", "format", "--check"]) + return code + + +def run_mypy() -> int: + """Run mypy type check.""" + code, _ = run_command(["mypy"]) + return code + + +def run_spec_lint() -> int: + """Run ethereum-spec-lint check.""" + code, _ = run_command(["ethereum-spec-lint"]) + return code + + +def run_lockcheck() -> int: + """Run uv lock --check.""" + code, _ = run_command(["uv", "lock", "--check"]) + return code + + +def run_actionlint() -> int: + """Run actionlint on GitHub workflows.""" + code, _ = run_command( + [ + "actionlint", + "-pyflakes", + "pyflakes", + "-shellcheck", + "shellcheck -S warning", + ] + ) + return code + + +def run_markdownlint() -> int: + """Run markdownlint-cli2 on markdown files.""" + if not shutil.which("markdownlint-cli2"): + print( + "markdownlint-cli2 not found.\n" + "This Node.js tool must be installed separately:\n" + "https://github.com/DavidAnson/markdownlint-cli2#install", + file=sys.stderr, + ) + return 1 + code, _ = run_command(["markdownlint-cli2", "./docs/**/*.md", "./*.md"]) + return code + + +def run_changelog() -> int: + """Validate changelog formatting (bullet points end with . or :).""" + project_root = find_project_root() + changelog_path = project_root / "docs" / "CHANGELOG.md" + + if not changelog_path.exists(): + print( + f"āŒ Changelog file not found: {changelog_path}", file=sys.stderr + ) + return 1 + + try: + content = changelog_path.read_text(encoding="utf-8") + except Exception as e: + print(f"āŒ Error reading changelog: {e}", file=sys.stderr) + return 1 + + # Find bullet points that don't end with period or colon + invalid_lines = [] + for line_num, line in enumerate(content.splitlines(), 1): + if re.match(r"^\s*-\s+", line) and re.search( + r"[^\.:]$", line.rstrip() + ): + invalid_lines.append((line_num, line.strip())) + + if invalid_lines: + print( + f"āŒ Bullet points in {changelog_path} lack proper punctuation:\n" + ) + for line_num, line in invalid_lines: + print(f"Line {line_num}: {line}") + print("\nšŸ’” All bullet points should end with:") + print(" - A period (.) for regular entries.") + print(" - A colon (:) for paragraphs that introduce lists.") + return 1 + else: + print("āœ… All bullet points have proper punctuation!") + return 0 + + +# Check registry +CHECKS: dict[str, Check] = { + "spellcheck": Check( + name="Spellcheck (via codespell)", + fix_hint=( + "If false positive, add to whitelist:\n" + "```bash\n" + "uv run whitelist \n" + "```\n\n" + "To auto-fix interactively:\n" + "```bash\n" + "uv run codespell -i 3\n" + "```" + ), + verify_cmd="uv run codespell", + run=run_codespell, + ), + "lint": Check( + name="Python lint check (via ruff)", + fix_hint=( + "To (potentially) auto-fix:\n```bash\nuv run ruff check --fix\n```" + ), + verify_cmd="uv run ruff check", + run=run_ruff_check, + ), + "format": Check( + name="Python format check (via ruff)", + fix_hint=("To auto-fix:\n```bash\nuv run ruff format\n```"), + verify_cmd="uv run ruff format --check", + run=run_ruff_format, + ), + "typecheck": Check( + name="Python typecheck (via mypy)", + fix_hint="No autofix. Fix the type errors above manually.", + verify_cmd="uv run mypy", + run=run_mypy, + ), + "spec-lint": Check( + name="Ethereum spec lint check", + fix_hint="No autofix. Fix the spec issues above.", + verify_cmd="uv run ethereum-spec-lint", + run=run_spec_lint, + ), + "lockcheck": Check( + name="Lock file check (via uv)", + fix_hint=( + "To sync the lock file:\n" + "```bash\n" + "uv lock\n" + "```\n\n" + "Then commit the updated uv.lock." + ), + verify_cmd="uv lock --check", + run=run_lockcheck, + ), + "actionlint": Check( + name="GitHub Actions workflow check (via actionlint)", + fix_hint="No autofix. Fix the workflow issues above.", + verify_cmd="uv run actionlint", + run=run_actionlint, + ), + "markdownlint": Check( + name="Markdown lint check (via markdownlint-cli2)", + fix_hint=( + "Ensure markdownlint-cli2 is installed, then fix the issues above." + ), + verify_cmd="markdownlint-cli2 './docs/**/*.md' './*.md'", + run=run_markdownlint, + ), + "changelog": Check( + name="Changelog validation", + fix_hint="Ensure bullet points end with `.` or `:`.", + verify_cmd="python scripts/fast_checks.py changelog", + run=run_changelog, + ), +} + + +def main() -> None: + """Main entry point.""" + parser = argparse.ArgumentParser( + description="Run static checks with fix hints on failure.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog="Example: python scripts/fast_checks.py lint", + ) + parser.add_argument( + "check", + choices=list(CHECKS.keys()), + help="The check to run", + ) + + args = parser.parse_args() + check = CHECKS[args.check] + + exit_code = check.run() + + if exit_code != 0: + print_fix_hint(check) + # Only show aggregate hint when not running under tox + if "TOX_ENV_NAME" not in os.environ: + print( + "\nRun all fast checks: tox -e fast-checks\n", file=sys.stderr + ) + # For changelog, we already built the output message + if args.check != "changelog": + write_github_summary(check, args.check, "See check output above") + + sys.exit(exit_code) + + +if __name__ == "__main__": + main() diff --git a/tox.ini b/tox.ini index ceef9663c5b..0c76d1cfda4 100644 --- a/tox.ini +++ b/tox.ini @@ -35,34 +35,42 @@ runner = uv-venv-lock-runner uv_seed = false wheel_build_env = .pkg -# Individual static check environments +# Individual static check environments (use scripts/fast_checks.py for fix hints) [testenv:spellcheck] description = Run spelling check using codespell -commands = codespell +commands = python scripts/fast_checks.py spellcheck [testenv:lint] description = Run linting checks using ruff -commands = ruff check +commands = python scripts/fast_checks.py lint [testenv:format] description = Run code formatting checks using ruff -commands = ruff format --check +commands = python scripts/fast_checks.py format [testenv:typecheck] description = Run type checking using mypy -commands = mypy +commands = python scripts/fast_checks.py typecheck [testenv:spec-lint] description = Run Ethereum specification custom lints -commands = ethereum-spec-lint +commands = python scripts/fast_checks.py spec-lint [testenv:lockcheck] description = Verify uv.lock is in sync with pyproject.toml -commands = uv lock --check +commands = python scripts/fast_checks.py lockcheck [testenv:actionlint] description = Run linting on GitHub Actions workflow files -commands = actionlint -pyflakes pyflakes -shellcheck "shellcheck -S warning" +commands = python scripts/fast_checks.py actionlint + +[testenv:markdownlint] +description = Lint markdown files using markdownlint-cli2 +commands = python scripts/fast_checks.py markdownlint + +[testenv:changelog] +description = Validate docs/CHANGELOG.md entries +commands = python scripts/fast_checks.py changelog # Aggregate alias - runs all fast static checks in sequence [testenv:fast-checks] @@ -265,11 +273,3 @@ setenv = DYLD_FALLBACK_LIBRARY_PATH = /opt/homebrew/lib commands = mkdocs build --strict - -[testenv:changelog] -description = Validate docs/CHANGELOG.md entries -commands = validate_changelog - -[testenv:markdownlint] -description = Lint markdown files (markdownlint) -commands = markdownlintcli2_soft_fail From c89a0172755cf90e16b5c573c57a7e175f608b94 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 00:47:31 +0100 Subject: [PATCH 03/12] refactor(testing): remove legacy tox_helpers.py Remove tox_helpers.py and its entry points, now replaced by scripts/fast_checks.py: - pyspelling_soft_fail: replaced by spellcheck (via codespell). - markdownlintcli2_soft_fail: replaced by markdownlint check. - validate_changelog: replaced by changelog check. Ref: ethereum/execution-specs#2041 --- packages/testing/pyproject.toml | 3 - .../src/execution_testing/cli/tox_helpers.py | 272 ------------------ 2 files changed, 275 deletions(-) delete mode 100644 packages/testing/src/execution_testing/cli/tox_helpers.py diff --git a/packages/testing/pyproject.toml b/packages/testing/pyproject.toml index dcc4d4af68d..17989515197 100644 --- a/packages/testing/pyproject.toml +++ b/packages/testing/pyproject.toml @@ -88,8 +88,6 @@ checklist = "execution_testing.cli.pytest_commands.checklist:checklist" generate_checklist_stubs = "execution_testing.cli.generate_checklist_stubs:generate_checklist_stubs" genindex = "execution_testing.cli.gen_index:generate_fixtures_index_cli" gentest = "execution_testing.cli.gentest:generate" -pyspelling_soft_fail = "execution_testing.cli.tox_helpers:pyspelling" -markdownlintcli2_soft_fail = "execution_testing.cli.tox_helpers:markdownlint" order_fixtures = "execution_testing.cli.order_fixtures:order_fixtures" evm_bytes = "execution_testing.cli.evm_bytes:evm_bytes" hasher = "execution_testing.cli.hasher:main" @@ -99,7 +97,6 @@ groupstats = "execution_testing.cli.show_pre_alloc_group_stats:main" extract_config = "execution_testing.cli.extract_config:extract_config" compare_fixtures = "execution_testing.cli.compare_fixtures:main" modify_static_test_gas_limits = "execution_testing.cli.modify_static_test_gas_limits:main" -validate_changelog = "execution_testing.cli.tox_helpers:validate_changelog" benchmark_parser = "execution_testing.cli.benchmark_parser:main" [tool.setuptools.packages.find] diff --git a/packages/testing/src/execution_testing/cli/tox_helpers.py b/packages/testing/src/execution_testing/cli/tox_helpers.py deleted file mode 100644 index 551e90b627b..00000000000 --- a/packages/testing/src/execution_testing/cli/tox_helpers.py +++ /dev/null @@ -1,272 +0,0 @@ -""" -CLI commands used by tox.ini. - -Contains wrappers to the external commands markdownlint-cli2 and pyspelling -(requires aspell) that fail silently if the command is not available. The aim -is to avoid disruption to external contributors. -""" - -import os -import re -import shutil -import subprocess -import sys -from pathlib import Path - -import click -from pyspelling import __main__ as pyspelling_main # type: ignore -from rich.console import Console - - -def write_github_summary( - title: str, tox_env: str, error_message: str, fix_commands: list[str] -) -> None: - """ - Write a summary to GitHub Actions when a check fails. - - Args: - title: The title of the check that failed tox_env: The tox - environment name (e.g., "spellcheck") - tox_env: The tox environment - error_message: Description of what went wrong - fix_commands: List of commands to fix the issue locally - - """ - if not os.environ.get("GITHUB_ACTIONS"): - return - - summary_file = os.environ.get("GITHUB_STEP_SUMMARY") - if not summary_file: - return - - with open(summary_file, "a") as f: - f.write(f"## āŒ {title}\n\n") - f.write(f"{error_message}\n\n") - f.write("### To reproduce this check locally:\n") - f.write("```bash\n") - f.write(f"uvx tox -e {tox_env}\n") - f.write("```\n\n") - - if fix_commands: - f.write("### To verify and fix the issues:\n") - f.write("```bash\n") - for cmd in fix_commands: - f.write(f"{cmd}\n") - f.write("```\n") - - -def find_project_root() -> Path: - """Locate the root directory of this project.""" - # Search upwards from file location - script_dir = Path(__file__).resolve().parent - for parent in [script_dir, *script_dir.parents]: - if (parent / "pyproject.toml").exists() and (parent / ".git").exists(): - return parent - - raise FileNotFoundError( - "Unable to locate project root! " - "Looking for a directory with both pyproject.toml and .git." - ) - - -@click.command( - context_settings={ - "ignore_unknown_options": True, - "allow_extra_args": True, - } -) -@click.argument("args", nargs=-1, type=click.UNPROCESSED) -def markdownlint(args: tuple[str, ...]) -> None: - """ - Lint the markdown in ./README.md and ./docs/ using the external command - markdownlint-cli2. - - Silently fail if markdownlint-cli2 is not installed. - - Allows argument forwarding to markdownlint-cli2. - """ - markdownlint = shutil.which("markdownlint-cli2") - if not markdownlint: - # Note: There's an additional step in test.yaml to run markdownlint- - # cli2 in GitHub Actions - click.echo( - "********* Install 'markdownlint-cli2' to enable markdown linting\ - *********\ - ```\ - sudo npm install -g markdownlint-cli2@0.17.2\ - ```\ - " - ) - sys.exit(0) - - args_list: list[str] = ( - list(args) if len(args) > 0 else ["./docs/**/*.md", "./*.md"] - ) - - command = ["node", markdownlint] + args_list - sys.exit(subprocess.run(command).returncode) - - -@click.command() -def pyspelling() -> None: - """ - Spellcheck the markdown in ./README.md and ./docs/ using the pyspelling - package. - - Silently fails if aspell is not installed (required by pyspelling). - - Command-line arguments are not forwarded to pyspelling. - """ - if not shutil.which("aspell"): - click.echo("aspell not installed, skipping spellcheck.") - if os.environ.get("GITHUB_ACTIONS"): - write_github_summary( - title="Pyspelling Check Failed", - tox_env="spellcheck", - error_message=( - "aspell is not installed. This tool is required for " - "spell checking documentation." - ), - fix_commands=[ - "# Install aspell on Ubuntu/Debian", - "sudo apt-get install aspell aspell-en", - "", - "# Install aspell on macOS", - "brew install aspell", - ], - ) - sys.exit(1) - else: - click.echo( - "********* Install 'aspell' and 'aspell-en' to enable " - "spellcheck *********" - ) - sys.exit(0) - - result = pyspelling_main.main() - if result != 0: - write_github_summary( - title="Pyspelling Check Failed", - tox_env="spellcheck", - error_message=( - "Pyspelling found spelling errors in the documentation." - ), - fix_commands=[ - "# Check the pyspelling configuration", - "cat .pyspelling.yml", - "", - "# Review and fix spelling errors manually", - "# Pyspelling doesn't have an auto-fix option", - ], - ) - sys.exit(result) - - -@click.command() -def codespell() -> None: - """ - Run codespell on the codebase and provide helpful error messages. - - Checks spelling in .github/, src/, tests/, and docs/ directories. - """ - console = Console() - - # Define the paths to check - paths_to_check = ["*.md", "*.ini", ".github/", "src/", "tests/", "docs/"] - paths_str = " ".join(paths_to_check) - - # Run codespell - result = subprocess.run( - ["codespell"] + paths_to_check, - capture_output=True, - text=True, - ) - - # Print the output - if result.stdout: - console.print(result.stdout) - if result.stderr: - console.print(result.stderr, style="red") - - # If there were spelling errors, show a helpful message - if result.returncode != 0: - console.print("\n[bold red]āŒ Spellcheck Failed[/bold red]") - console.print( - "[yellow]Please review the errors above. For single-suggestion " - "fixes, you can automatically apply them with:[/yellow]" - ) - console.print( - f"[cyan]uv run codespell {paths_str} --write-changes[/cyan]\n" - ) - - # Write to GitHub Actions summary - write_github_summary( - title="Spellcheck Failed", - tox_env="spellcheck", - error_message="Codespell found spelling errors in the code.", - fix_commands=[ - "# Ensure codespell is installed (part of docs extras)", - "uv sync", - "", - "# Check for spelling errors", - f"uv run codespell {paths_str}", - "", - "# Automatically fix single-suggestion errors", - f"uv run codespell {paths_str} --write-changes", - ], - ) - - sys.exit(1) - - sys.exit(0) - sys.exit(pyspelling_main.main()) - - -@click.command() -def validate_changelog() -> None: - """ - Validate changelog formatting to ensure bullet points end with proper - punctuation. - - Checks that all bullet points (including nested ones) end with either: - - A period (.) for regular entries - - A colon (:) for section headers that introduce lists - """ - project_root = find_project_root() - changelog_path = Path(project_root / "docs/CHANGELOG.md") - - if not changelog_path.exists(): - click.echo(f"āŒ Changelog file not found: {changelog_path}") - sys.exit(1) - - try: - with open(changelog_path, "r", encoding="utf-8") as f: - content = f.read() - except Exception as e: - click.echo(f"āŒ Error reading changelog: {e}.") - sys.exit(1) - - # Find bullet points that don't end with period or colon - invalid_lines = [] - for line_num, line in enumerate(content.splitlines(), 1): - if re.match(r"^\s*-\s+", line) and re.search( - r"[^\.:]$", line.rstrip() - ): - invalid_lines.append((line_num, line.strip())) - - if invalid_lines: - click.echo( - f"āŒ Found bullet points in {changelog_path} without proper " - "punctuation:" - ) - click.echo() - for line_num, line in invalid_lines: - click.echo(f"Line {line_num}: {line}") - click.echo() - click.echo("šŸ’” All bullet points should end with:") - click.echo(" - A period (.) for regular entries.") - click.echo(" - A colon (:) for paragraphs that introduce lists.") - sys.exit(1) - else: - click.echo("āœ… All bullet points have proper punctuation!") - sys.exit(0) From db481019d101321a83b5f45c650ce5c39885f1de Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 01:11:16 +0100 Subject: [PATCH 04/12] feat(ci): add fast-checks workflow for parallel static checks Add .github/workflows/fast-checks.yaml that runs all static checks in parallel via matrix jobs: - Spellcheck, Lint, Format, Typecheck, Spec Lint, Lock Check. - Action Lint, Changelog. - Markdown Lint (via dedicated GitHub Action). - SHA Pinned Actions check. Update workflows to use fast-checks as a prerequisite: - test.yaml: removed monolithic static job. - test-docs.yaml: removed duplicate changelog/markdownlint jobs. - benchmark.yaml: added fast-checks prerequisite. - hive-consume.yaml: added fast-checks prerequisite. --- .github/actionlint.yaml | 5 ++ .../actions/merge-eip-branches/action.yaml | 4 +- .github/actions/rebase-eip-branch/action.yaml | 4 +- .github/workflows/benchmark.yaml | 4 ++ .github/workflows/fast-checks.yaml | 58 +++++++++++++++++++ .github/workflows/hive-consume.yaml | 4 ++ .github/workflows/test-docs.yaml | 32 ++-------- .github/workflows/test.yaml | 45 +++----------- 8 files changed, 87 insertions(+), 69 deletions(-) create mode 100644 .github/workflows/fast-checks.yaml diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 21f071c6d70..f7759d16457 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -4,3 +4,8 @@ self-hosted-runner: - size-l-x64 - size-xl-x64 - size-gigachungus-x64 + +# Validate vars.* references in workflows +config-variables: + - DEFAULT_PYTHON_VERSION + - UV_VERSION diff --git a/.github/actions/merge-eip-branches/action.yaml b/.github/actions/merge-eip-branches/action.yaml index 3de3ecb5f24..5eb3625d6f6 100644 --- a/.github/actions/merge-eip-branches/action.yaml +++ b/.github/actions/merge-eip-branches/action.yaml @@ -113,8 +113,8 @@ runs: fi done - echo "Running static checks on merged branch" - uvx --with=tox-uv tox -e static + echo "Running fast checks on merged branch" + uvx tox -e fast-checks echo "All EIP branches merged successfully" diff --git a/.github/actions/rebase-eip-branch/action.yaml b/.github/actions/rebase-eip-branch/action.yaml index 82eeddbe7f8..e42f98b7abf 100644 --- a/.github/actions/rebase-eip-branch/action.yaml +++ b/.github/actions/rebase-eip-branch/action.yaml @@ -57,8 +57,8 @@ runs: exit 1 fi - echo "Running static checks on rebased branch" - uvx --with=tox-uv tox -e static + echo "Running fast checks on rebased branch" + uvx tox -e fast-checks echo "Rebase successful" diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 532f765ce21..32294198f83 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -26,8 +26,12 @@ concurrency: cancel-in-progress: true jobs: + fast-checks: + uses: ./.github/workflows/fast-checks.yaml + unit-tests: name: Benchmark Unit Tests + needs: fast-checks runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 diff --git a/.github/workflows/fast-checks.yaml b/.github/workflows/fast-checks.yaml new file mode 100644 index 00000000000..69ae0c5f4ed --- /dev/null +++ b/.github/workflows/fast-checks.yaml @@ -0,0 +1,58 @@ +name: Fast Checks + +on: + push: + pull_request: + workflow_dispatch: + workflow_call: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + checks: + name: ${{ matrix.name }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - { name: "Spellcheck", tox-env: spellcheck } + - { name: "Python Lint", tox-env: lint } + - { name: "Python Format", tox-env: format } + - { name: "Python Typecheck", tox-env: typecheck } + - { name: "Spec Lint", tox-env: spec-lint } + - { name: "Lock Check", tox-env: lockcheck } + - { name: "Action Lint", tox-env: actionlint } + - { name: "Changelog", tox-env: changelog } + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Install uv and Python + uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 + with: + enable-cache: true + cache-dependency-glob: "uv.lock" + version: ${{ vars.UV_VERSION }} + python-version: ${{ vars.DEFAULT_PYTHON_VERSION }} + - name: Run ${{ matrix.name }} + run: uvx tox -e ${{ matrix.tox-env }} + + markdownlint: + name: Markdown Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 + with: + globs: | + docs/**/*.md + *.md + + sha-pinned-actions: + name: SHA Pinned Actions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Ensure SHA pinned actions + uses: zgosalvez/github-actions-ensure-sha-pinned-actions@6124774845927d14c601359ab8138699fa5b70c3 diff --git a/.github/workflows/hive-consume.yaml b/.github/workflows/hive-consume.yaml index d2374b13063..b9832533f8d 100644 --- a/.github/workflows/hive-consume.yaml +++ b/.github/workflows/hive-consume.yaml @@ -48,8 +48,12 @@ env: FIXTURES_URL: https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz jobs: + fast-checks: + uses: ./.github/workflows/fast-checks.yaml + cache-docker-images: name: Cache Docker Images + needs: fast-checks runs-on: [self-hosted-ghr, size-l-x64] steps: - name: Checkout execution-specs diff --git a/.github/workflows/test-docs.yaml b/.github/workflows/test-docs.yaml index 1595168af06..b746a9bb2d4 100644 --- a/.github/workflows/test-docs.yaml +++ b/.github/workflows/test-docs.yaml @@ -23,8 +23,12 @@ concurrency: cancel-in-progress: true jobs: + fast-checks: + uses: ./.github/workflows/fast-checks.yaml + mkdocs: name: Test html documentation build with mkdocs + needs: fast-checks runs-on: ubuntu-latest steps: - name: Checkout ethereum/execution-specs @@ -38,31 +42,3 @@ jobs: python-version: ${{ vars.DEFAULT_PYTHON_VERSION }} - name: Build html documentation with mkdocs via tox run: uvx tox -e mkdocs - - changelog: - name: Validate changelog entries - runs-on: ubuntu-latest - steps: - - name: Checkout ethereum/execution-specs - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - name: Install uv ${{ vars.UV_VERSION }} and python ${{ vars.DEFAULT_PYTHON_VERSION }} - uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 - with: - enable-cache: true - cache-dependency-glob: "uv.lock" - version: ${{ vars.UV_VERSION }} - python-version: ${{ vars.DEFAULT_PYTHON_VERSION }} - - name: Run changelog validation via tox - run: uvx tox -e changelog - - markdownlint: - name: Lint markdown files with markdownlint - runs-on: ubuntu-latest - steps: - - name: Checkout ethereum/execution-specs - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 - with: - globs: | - docs/**/*.md - *.md diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2e502b7af58..8bbc527a937 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,41 +30,12 @@ concurrency: cancel-in-progress: true jobs: - static: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 - with: - submodules: recursive - - name: Ensure SHA pinned actions - uses: zgosalvez/github-actions-ensure-sha-pinned-actions@6124774845927d14c601359ab8138699fa5b70c3 # v4.0.1 - - name: Setup Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 - with: - python-version: "3.11" - - name: Install Tox and any other packages - shell: bash - run: | - sudo DEBIAN_FRONTEND=noninteractive apt-get install --yes --force-yes build-essential pkg-config - pip install 'tox>=4.11,<5' requests - - name: Run static checks - run: tox -e static - - name: Setup uv - uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1 - - name: Validate workflow config variables - run: | - cat >> .github/actionlint.yaml << 'EOF' - - # CI-only: validate vars.* references - config-variables: - - DEFAULT_PYTHON_VERSION - - UV_VERSION - EOF - uvx --from actionlint-py actionlint + fast-checks: + uses: ./.github/workflows/fast-checks.yaml py3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -85,7 +56,7 @@ jobs: pypy3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -103,7 +74,7 @@ jobs: json_infra: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -121,7 +92,7 @@ jobs: optimized: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -139,7 +110,7 @@ jobs: tests_pytest_py3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -155,7 +126,7 @@ jobs: tests_pytest_pypy3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: static + needs: fast-checks steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: From daca85b86f5f29a3f508c6304537844d9c73efdd Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 01:23:56 +0100 Subject: [PATCH 05/12] docs: update documentation for fast-checks and pre-commit - Add `fast-checks` to tox command table in code_standards.md. - Document fix hints feature with example output. - Update recommended commands to use `fast-checks`. - Add pre-commit hooks table to precommit.md. - Update PR template to use `fast-checks`. - Update EIP author manual to use `fast-checks`. - Add .pre-commit-config.yaml for local development. --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .pre-commit-config.yaml | 66 ++++++++++++++++++++++++++ EIP_AUTHORS_MANUAL.md | 2 +- docs/dev/precommit.md | 27 +++++++++++ docs/getting_started/code_standards.md | 36 ++++++++++---- 5 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0d5b8b038dc..9fda94f887a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ N/A. - [ ] All: Ran fast `tox` checks to avoid unnecessary CI fails, see also [Code Standards](https://eest.ethereum.org/main/getting_started/code_standards/) and [Enabling Pre-commit Checks](https://eest.ethereum.org/main/dev/precommit/): ```console - uvx tox -e static + uvx tox -e fast-checks ``` - [ ] All: PR title adheres to the [repo standard](https://eest.ethereum.org/main/getting_started/contributing/?h=contri#commit-messages-issue-and-pr-titles) - it will be used as the squash commit message and should start `type(scope):`. - [ ] All: Considered updating the online docs in the [./docs/](/ethereum/execution-specs/blob/HEAD/docs/) directory. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..257c4b48db2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-added-large-files + + - repo: local + hooks: + # Fast file-level checks (run on changed files only) + - id: ruff-check + name: Python lint (ruff) + entry: uv run ruff check --fix + language: system + types: [python] + + - id: ruff-format + name: Python format (ruff) + entry: uv run ruff format + language: system + types: [python] + + - id: codespell + name: Spellcheck (codespell) + entry: uv run codespell + language: system + types_or: [python, markdown, yaml, ini] + + # Project-level checks (run on whole project) + - id: mypy + name: Python typecheck (mypy) + entry: uv run mypy + language: system + types: [python] + pass_filenames: false + + - id: spec-lint + name: Ethereum spec lint + entry: uv run ethereum-spec-lint + language: system + types: [python] + pass_filenames: false + + - id: lockcheck + name: Lock file check (uv) + entry: uv lock --check + language: system + files: ^(pyproject\.toml|uv\.lock)$ + pass_filenames: false + + - id: actionlint + name: GitHub Actions lint + entry: uv run actionlint + language: system + files: ^\.github/workflows/.*\.ya?ml$ + pass_filenames: false + + - id: changelog + name: Changelog validation + entry: uv run python scripts/fast_checks.py changelog + language: system + files: ^docs/CHANGELOG\.md$ + pass_filenames: false diff --git a/EIP_AUTHORS_MANUAL.md b/EIP_AUTHORS_MANUAL.md index 2d549e23cfb..b43cf67f67e 100644 --- a/EIP_AUTHORS_MANUAL.md +++ b/EIP_AUTHORS_MANUAL.md @@ -54,7 +54,7 @@ Implementing a new EIP in the `execution-specs` repository involves the followin 1. **Create a new branch**: Create a new branch for the EIP under the appropriate fork. For example, if you are implementing an EIP for the Prague fork, create a new branch under `eips//eip-`. 2. **Implement the EIP**: Implement the EIP in the `src/ethereum/` folder. -3. **Basic sanity checks**: Run `tox -e static` to run basic formatting and linting checks. +3. **Basic sanity checks**: Run `tox -e fast-checks` to run basic formatting and linting checks. 4. **Raise a PR**: Raise a PR against the appropriate branch. For example, if you are implementing an EIP for the Prague fork, raise a PR against the `forks/prague` branch. An EIP can only be CFI'd (Considered For Inclusion) if it has a reference `execution-specs` implementation. The EIP author is responsible for maintaining their EIP up-to-date with the latest changes. For example, if an author had written their EIP for Cancun under `eips/cancun/eip-x`, but for some reason it didn't make it into Cancun, they would need to rebase their EIP to reflect the changes in Prague under `eips/prague/eip-x`. diff --git a/docs/dev/precommit.md b/docs/dev/precommit.md index 3b8af55539d..ca3ed12f785 100644 --- a/docs/dev/precommit.md +++ b/docs/dev/precommit.md @@ -8,6 +8,33 @@ To enable pre-commit, the following must be run once: uvx pre-commit install ``` +## What Gets Checked + +Pre-commit runs the following checks on staged files: + +| Check | Description | +|-------|-------------| +| `trailing-whitespace` | Removes trailing whitespace. | +| `end-of-file-fixer` | Ensures files end with a newline. | +| `check-yaml` | Validates YAML syntax. | +| `check-toml` | Validates TOML syntax. | +| `check-added-large-files` | Prevents large files from being committed. | +| `ruff check` | Python linting with auto-fix. | +| `ruff format` | Python formatting. | +| `codespell` | Spelling check for code and docs. | +| `mypy` | Python type checking. | +| `ethereum-spec-lint` | Custom Ethereum spec lints. | +| `uv lock --check` | Ensures lock file is up to date. | +| `actionlint` | GitHub Actions workflow validation. | +| `changelog` | Changelog format validation. | + +!!! tip "Running checks manually" + To run all fast checks without committing: + + ```console + uvx tox -e fast-checks + ``` + !!! note "Bypassing pre-commit checks" Enabling of pre-commit checks is not mandatory (it cannot be enforced) and even if it is enabled, it can always be bypassed with: diff --git a/docs/getting_started/code_standards.md b/docs/getting_started/code_standards.md index e39a8373997..d56c0b3630f 100644 --- a/docs/getting_started/code_standards.md +++ b/docs/getting_started/code_standards.md @@ -8,13 +8,15 @@ Code pushed to @ethereum/execution-specs must fulfill the following checks in [C | Type | Tox Command | Explanation | | ---------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| Lint & code formatting | `uvx tox -e lint` | Python lint, format and module import check via `ruff` | +| **All fast checks** | `uvx tox -e fast-checks` | Run all fast static checks (lint, format, typecheck, spellcheck, etc.) in sequence. | +| Lint | `uvx tox -e lint` | Python lint check via `ruff`. | +| Format | `uvx tox -e format` | Python code formatting check via `ruff`. | | Typecheck | `uvx tox -e typecheck` | Objects that provide typehints pass type-checking via `mypy`. | | Framework unit tests | `uvx tox -e tests_pytest_py3` | All framework unit tests must execute correctly. | | Fill tests | `uvx tox -e py3` | All test cases for deployed forks can be generated. | | Benchmark tests | `uvx tox -e benchmark-gas-values` | Benchmark test cases can be generated. | | HTML doc build | `uvx tox -e mkdocs` | Documentation generated without warnings. | -| Spellcheck | `uvx tox -e spellcheck` | Code and documentation spell-check using codespell. | +| Spellcheck | `uvx tox -e spellcheck` | Code and documentation spell-check using codespell. | | Markdown lint | `uvx tox -e markdownlint` | Markdown lint (requires [additional dependency](code_standards_details.md#additional-dependencies)). | | Changelog validation | `uvx tox -e changelog` | Validates changelog entries format and structure in `docs/CHANGELOG.md`. | @@ -25,7 +27,7 @@ Code pushed to @ethereum/execution-specs must fulfill the following checks in [C ```console uvx pre-commit install ``` - + This saves you time by catching formatting issues, type errors, and spelling mistakes before they reach CI. !!! tip "Running checks easily" @@ -36,24 +38,42 @@ Code pushed to @ethereum/execution-specs must fulfill the following checks in [C alias tox="uvx tox" ``` - Run all checks in parallel: + Run all fast static checks (recommended before pushing): ```console - uvx tox run-parallel + uvx tox -e fast-checks ``` - Run sequentially: + Run all checks in parallel: ```console - uvx tox + uvx tox run-parallel ``` - Run specific, faster checks: + Run specific checks: ```console uvx tox -e lint,typecheck ``` +!!! info "Fix hints on failure" + + When a check fails, you'll see a **fix hint** with instructions on how to resolve the issue: + + ``` + ============================================================ + Python lint check (via ruff) failed: + ============================================================ + Try: + uv run ruff check --fix . + + Verify: + uv run ruff check + ============================================================ + ``` + + In GitHub Actions, these hints also appear in the job summary for easy access. + !!! tip "Lint & code formatting: Using `ruff` and VS Code to help autoformat and fix module imports" On the command-line, solve fixable issues with: From e59d99fbb1e5cc8e3819d98b9816c675709bad53 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 09:55:44 +0100 Subject: [PATCH 06/12] feat(tooling): add Justfile and rename fast-checks to check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename tox env `fast-checks` → `check` for consistency - Rename workflow `fast-checks.yaml` → `check.yaml` - Update all workflow refs (`uses:`, `needs:`) to use `check` - Update GitHub Actions to use `tox -e check` - Add fix hints showing `just fix` / `make fix` for lint/format - Create Justfile with recipes delegating to tox - Keep `static` as backwards-compat alias for `check` --- .../actions/merge-eip-branches/action.yaml | 4 +- .github/actions/rebase-eip-branch/action.yaml | 4 +- .github/workflows/benchmark.yaml | 6 +- .../{fast-checks.yaml => check.yaml} | 2 +- .github/workflows/hive-consume.yaml | 6 +- .github/workflows/test-docs.yaml | 6 +- .github/workflows/test.yaml | 16 +++--- Justfile | 57 +++++++++++++++++++ scripts/fast_checks.py | 24 ++++++-- tox.ini | 10 ++-- 10 files changed, 103 insertions(+), 32 deletions(-) rename .github/workflows/{fast-checks.yaml => check.yaml} (99%) create mode 100644 Justfile diff --git a/.github/actions/merge-eip-branches/action.yaml b/.github/actions/merge-eip-branches/action.yaml index 5eb3625d6f6..0bcb6a0b00f 100644 --- a/.github/actions/merge-eip-branches/action.yaml +++ b/.github/actions/merge-eip-branches/action.yaml @@ -113,8 +113,8 @@ runs: fi done - echo "Running fast checks on merged branch" - uvx tox -e fast-checks + echo "Running static checks on merged branch" + uvx tox -e check echo "All EIP branches merged successfully" diff --git a/.github/actions/rebase-eip-branch/action.yaml b/.github/actions/rebase-eip-branch/action.yaml index e42f98b7abf..c80b14dc07e 100644 --- a/.github/actions/rebase-eip-branch/action.yaml +++ b/.github/actions/rebase-eip-branch/action.yaml @@ -57,8 +57,8 @@ runs: exit 1 fi - echo "Running fast checks on rebased branch" - uvx tox -e fast-checks + echo "Running static checks on rebased branch" + uvx tox -e check echo "Rebase successful" diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 32294198f83..3bea510b35e 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -26,12 +26,12 @@ concurrency: cancel-in-progress: true jobs: - fast-checks: - uses: ./.github/workflows/fast-checks.yaml + check: + uses: ./.github/workflows/check.yaml unit-tests: name: Benchmark Unit Tests - needs: fast-checks + needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 diff --git a/.github/workflows/fast-checks.yaml b/.github/workflows/check.yaml similarity index 99% rename from .github/workflows/fast-checks.yaml rename to .github/workflows/check.yaml index 69ae0c5f4ed..75fb19cb1c9 100644 --- a/.github/workflows/fast-checks.yaml +++ b/.github/workflows/check.yaml @@ -1,4 +1,4 @@ -name: Fast Checks +name: Check on: push: diff --git a/.github/workflows/hive-consume.yaml b/.github/workflows/hive-consume.yaml index b9832533f8d..d2be1937051 100644 --- a/.github/workflows/hive-consume.yaml +++ b/.github/workflows/hive-consume.yaml @@ -48,12 +48,12 @@ env: FIXTURES_URL: https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz jobs: - fast-checks: - uses: ./.github/workflows/fast-checks.yaml + check: + uses: ./.github/workflows/check.yaml cache-docker-images: name: Cache Docker Images - needs: fast-checks + needs: check runs-on: [self-hosted-ghr, size-l-x64] steps: - name: Checkout execution-specs diff --git a/.github/workflows/test-docs.yaml b/.github/workflows/test-docs.yaml index b746a9bb2d4..fa3ca2ed805 100644 --- a/.github/workflows/test-docs.yaml +++ b/.github/workflows/test-docs.yaml @@ -23,12 +23,12 @@ concurrency: cancel-in-progress: true jobs: - fast-checks: - uses: ./.github/workflows/fast-checks.yaml + check: + uses: ./.github/workflows/check.yaml mkdocs: name: Test html documentation build with mkdocs - needs: fast-checks + needs: check runs-on: ubuntu-latest steps: - name: Checkout ethereum/execution-specs diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8bbc527a937..82885f15419 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,12 +30,12 @@ concurrency: cancel-in-progress: true jobs: - fast-checks: - uses: ./.github/workflows/fast-checks.yaml + check: + uses: ./.github/workflows/check.yaml py3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -56,7 +56,7 @@ jobs: pypy3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -74,7 +74,7 @@ jobs: json_infra: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -92,7 +92,7 @@ jobs: optimized: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -110,7 +110,7 @@ jobs: tests_pytest_py3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: @@ -126,7 +126,7 @@ jobs: tests_pytest_pypy3: runs-on: [self-hosted-ghr, size-xl-x64] - needs: fast-checks + needs: check steps: - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 with: diff --git a/Justfile b/Justfile new file mode 100644 index 00000000000..e33feeffc81 --- /dev/null +++ b/Justfile @@ -0,0 +1,57 @@ +# Justfile for ethereum/execution-specs +# All recipes delegate to tox (source of truth) + +set quiet := true + +default: + @just --list + +# Static checks +check: + uvx tox -e check + +lint: + uvx tox -e lint + +format: + uvx tox -e format + +typecheck: + uvx tox -e typecheck + +spellcheck: + uvx tox -e spellcheck + +spec-lint: + uvx tox -e spec-lint + +lockcheck: + uvx tox -e lockcheck + +actionlint: + uvx tox -e actionlint + +markdownlint: + uvx tox -e markdownlint + +changelog: + uvx tox -e changelog + +# Auto-fix lint and format issues (runs uv directly, no tox env) +fix: + uv run ruff check --fix + uv run ruff format + +# Tests +test: + uvx tox -e py3 + +test-unit: + uvx tox -e tests_pytest_py3 + +# Documentation +docs: + uvx tox -e mkdocs + +docs-serve: + FAST_DOCS=True uv run mkdocs serve diff --git a/scripts/fast_checks.py b/scripts/fast_checks.py index 230311785fa..dda6f17be27 100644 --- a/scripts/fast_checks.py +++ b/scripts/fast_checks.py @@ -236,14 +236,30 @@ def run_changelog() -> int: "lint": Check( name="Python lint check (via ruff)", fix_hint=( - "To (potentially) auto-fix:\n```bash\nuv run ruff check --fix\n```" + "To (potentially) auto-fix:\n" + "```bash\n" + "uv run ruff check --fix\n" + "```\n\n" + "Or fix all lint/format issues:\n" + "```bash\n" + "just fix # or: make fix\n" + "```" ), verify_cmd="uv run ruff check", run=run_ruff_check, ), "format": Check( name="Python format check (via ruff)", - fix_hint=("To auto-fix:\n```bash\nuv run ruff format\n```"), + fix_hint=( + "To auto-fix:\n" + "```bash\n" + "uv run ruff format\n" + "```\n\n" + "Or fix all lint/format issues:\n" + "```bash\n" + "just fix # or: make fix\n" + "```" + ), verify_cmd="uv run ruff format --check", run=run_ruff_format, ), @@ -316,9 +332,7 @@ def main() -> None: print_fix_hint(check) # Only show aggregate hint when not running under tox if "TOX_ENV_NAME" not in os.environ: - print( - "\nRun all fast checks: tox -e fast-checks\n", file=sys.stderr - ) + print("\nRun all static checks: tox -e check\n", file=sys.stderr) # For changelog, we already built the output message if args.check != "changelog": write_github_summary(check, args.check, "See check output above") diff --git a/tox.ini b/tox.ini index 0c76d1cfda4..a8a5ea00eeb 100644 --- a/tox.ini +++ b/tox.ini @@ -27,7 +27,7 @@ envlist = markdownlint changelog # Aggregate aliases - fast-checks + check static [testenv] @@ -73,8 +73,8 @@ description = Validate docs/CHANGELOG.md entries commands = python scripts/fast_checks.py changelog # Aggregate alias - runs all fast static checks in sequence -[testenv:fast-checks] -description = Run all fast static checks (spelling, lint, format, typecheck, spec-lint, lock, actions, markdown, changelog) +[testenv:check] +description = Run all static checks (spelling, lint, format, typecheck, spec-lint, lock, actions, markdown, changelog) commands = {[testenv:spellcheck]commands} {[testenv:lint]commands} @@ -88,8 +88,8 @@ commands = # Backwards compatibility alias [testenv:static] -description = Run all static checks (alias for fast-checks) -commands = {[testenv:fast-checks]commands} +description = Run all static checks (alias for check) +commands = {[testenv:check]commands} [testenv:tests_pytest_py3] description = Run the testing package unit tests (with Python) From e3fdd4df137477466c6d9ac3dfec9e27a82cc507 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 09:55:59 +0100 Subject: [PATCH 07/12] feat(tooling): add Makefile Add Makefile as alternative entry point for running checks. All targets delegate to tox (source of truth). Includes `make help` for discoverability. --- Makefile | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..ab9812f25f7 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +# Makefile for ethereum/execution-specs and Marius +# All targets delegate to tox (source of truth) + +.PHONY: help check lint format typecheck spellcheck spec-lint lockcheck \ + actionlint markdownlint changelog fix test test-unit docs docs-serve + +.DEFAULT_GOAL := help + +help: ## Show this help + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-18s\033[0m %s\n", $$1, $$2}' + +check: ## Run all static checks + uvx tox -e check + +lint: ## Python linting (ruff) + uvx tox -e lint + +format: ## Python format check (ruff) + uvx tox -e format + +typecheck: ## Python type check (mypy) + uvx tox -e typecheck + +spellcheck: ## Spelling check (codespell) + uvx tox -e spellcheck + +spec-lint: ## Ethereum spec lints + uvx tox -e spec-lint + +lockcheck: ## Verify uv.lock in sync + uvx tox -e lockcheck + +actionlint: ## GitHub Actions lint + uvx tox -e actionlint + +markdownlint: ## Markdown lint + uvx tox -e markdownlint + +changelog: ## Changelog validation + uvx tox -e changelog + +fix: ## Auto-fix lint/format issues (runs uv directly) + uv run ruff check --fix + uv run ruff format + +test: ## Run test filler (py3) + uvx tox -e py3 + +test-unit: ## Run framework unit tests + uvx tox -e tests_pytest_py3 + +docs: ## Build HTML docs + uvx tox -e mkdocs + +docs-serve: ## Serve docs locally + FAST_DOCS=True uv run mkdocs serve From 40d4fb914dd16c7e9886e33d27f74ae16e8a6c63 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 09:57:24 +0100 Subject: [PATCH 08/12] docs: update documentation for check command and build tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update all `fast-checks` → `check` references in docs - Update CI workflow link to check.yaml - Show just/make/tox options in code standards table - Create docs/dev/build_tools.md with command reference - Update PR template and EIP authors manual --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- EIP_AUTHORS_MANUAL.md | 2 +- docs/dev/build_tools.md | 62 +++++++++++++++++++ docs/dev/precommit.md | 2 +- docs/dev/test_actions_locally.md | 26 ++++---- docs/getting_started/code_standards.md | 27 ++++---- .../getting_started/code_standards_details.md | 8 +-- docs/navigation.md | 1 + 8 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 docs/dev/build_tools.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9fda94f887a..c0d6587e51e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ N/A. - [ ] All: Ran fast `tox` checks to avoid unnecessary CI fails, see also [Code Standards](https://eest.ethereum.org/main/getting_started/code_standards/) and [Enabling Pre-commit Checks](https://eest.ethereum.org/main/dev/precommit/): ```console - uvx tox -e fast-checks + just check # or: make check, uvx tox -e check ``` - [ ] All: PR title adheres to the [repo standard](https://eest.ethereum.org/main/getting_started/contributing/?h=contri#commit-messages-issue-and-pr-titles) - it will be used as the squash commit message and should start `type(scope):`. - [ ] All: Considered updating the online docs in the [./docs/](/ethereum/execution-specs/blob/HEAD/docs/) directory. diff --git a/EIP_AUTHORS_MANUAL.md b/EIP_AUTHORS_MANUAL.md index b43cf67f67e..8057f91f392 100644 --- a/EIP_AUTHORS_MANUAL.md +++ b/EIP_AUTHORS_MANUAL.md @@ -54,7 +54,7 @@ Implementing a new EIP in the `execution-specs` repository involves the followin 1. **Create a new branch**: Create a new branch for the EIP under the appropriate fork. For example, if you are implementing an EIP for the Prague fork, create a new branch under `eips//eip-`. 2. **Implement the EIP**: Implement the EIP in the `src/ethereum/` folder. -3. **Basic sanity checks**: Run `tox -e fast-checks` to run basic formatting and linting checks. +3. **Basic sanity checks**: Run `just check # or: make check, tox -e check` to run basic formatting and linting checks. 4. **Raise a PR**: Raise a PR against the appropriate branch. For example, if you are implementing an EIP for the Prague fork, raise a PR against the `forks/prague` branch. An EIP can only be CFI'd (Considered For Inclusion) if it has a reference `execution-specs` implementation. The EIP author is responsible for maintaining their EIP up-to-date with the latest changes. For example, if an author had written their EIP for Cancun under `eips/cancun/eip-x`, but for some reason it didn't make it into Cancun, they would need to rebase their EIP to reflect the changes in Prague under `eips/prague/eip-x`. diff --git a/docs/dev/build_tools.md b/docs/dev/build_tools.md new file mode 100644 index 00000000000..bb42f6db7e7 --- /dev/null +++ b/docs/dev/build_tools.md @@ -0,0 +1,62 @@ +# Build Tools + +This repository provides three equivalent ways to run checks and common tasks: **Justfile**, **Makefile**, and **tox**. All three delegate to tox as the source of truth. + +## Quick Reference + +| Task | just | make | tox | +|------|------|------|-----| +| All static checks | `just check` | `make check` | `uvx tox -e check` | +| Python lint | `just lint` | `make lint` | `uvx tox -e lint` | +| Python format check | `just format` | `make format` | `uvx tox -e format` | +| Python typecheck | `just typecheck` | `make typecheck` | `uvx tox -e typecheck` | +| Spellcheck | `just spellcheck` | `make spellcheck` | `uvx tox -e spellcheck` | +| Spec lint | `just spec-lint` | `make spec-lint` | `uvx tox -e spec-lint` | +| Lock file check | `just lockcheck` | `make lockcheck` | `uvx tox -e lockcheck` | +| Actions lint | `just actionlint` | `make actionlint` | `uvx tox -e actionlint` | +| Markdown lint | `just markdownlint` | `make markdownlint` | `uvx tox -e markdownlint` | +| Changelog check | `just changelog` | `make changelog` | `uvx tox -e changelog` | +| **Auto-fix lint/format** | `just fix` | `make fix` | _(no tox env)_ | +| Run tests | `just test` | `make test` | `uvx tox -e py3` | +| Run unit tests | `just test-unit` | `make test-unit` | `uvx tox -e tests_pytest_py3` | +| Build docs | `just docs` | `make docs` | `uvx tox -e mkdocs` | +| Serve docs locally | `just docs-serve` | `make docs-serve` | _(direct uv run)_ | + +## When to Use Which Tool + +| Tool | Best For | Notes | +|------|----------|-------| +| **just** | Daily development | Short commands, tab completion, cross-platform | +| **make** | CI/scripts, familiarity | Universal availability, well-known | +| **tox** | Advanced usage | Full control, parallel runs, custom envs | + +## Listing Available Commands + +```console +just --list # List all just recipes +make help # Show make targets with descriptions +uvx tox -av # List all tox environments with descriptions +``` + +## Auto-fixing Issues + +The `fix` recipe runs ruff directly (not via tox) to auto-fix lint and format issues: + +```console +just fix # or: make fix +``` + +This is equivalent to: + +```console +uv run ruff check --fix +uv run ruff format +``` + +## Adding New Recipes + +When adding a new check or task: + +1. Add the tox environment in `tox.ini` (source of truth). +2. Add corresponding recipes to both `Justfile` and `Makefile`. +3. Keep the interface consistent across all three tools. diff --git a/docs/dev/precommit.md b/docs/dev/precommit.md index ca3ed12f785..e60faec5b7a 100644 --- a/docs/dev/precommit.md +++ b/docs/dev/precommit.md @@ -32,7 +32,7 @@ Pre-commit runs the following checks on staged files: To run all fast checks without committing: ```console - uvx tox -e fast-checks + uvx tox -e check ``` !!! note "Bypassing pre-commit checks" diff --git a/docs/dev/test_actions_locally.md b/docs/dev/test_actions_locally.md index e5fe9fee340..0a3079ea2cc 100644 --- a/docs/dev/test_actions_locally.md +++ b/docs/dev/test_actions_locally.md @@ -45,16 +45,16 @@ will output something similar to: ```bash INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock' Stage Job ID Job name Workflow name Workflow file Events -0 checks Spellcheck Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Python Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Python Format Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Python Typecheck Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Spec Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Lock Check Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Action Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 checks Changelog Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 markdownlint Markdown Lint Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call -0 sha-pinned-actions SHA Pinned Actions Fast Checks fast-checks.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Spellcheck Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Lint Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Format Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Python Typecheck Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Spec Lint Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Lock Check Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Action Lint Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 checks Changelog Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 markdownlint Markdown Lint Check check.yaml push,pull_request,workflow_dispatch,workflow_call +0 sha-pinned-actions SHA Pinned Actions Check check.yaml push,pull_request,workflow_dispatch,workflow_call ... ``` @@ -72,7 +72,7 @@ DEFAULT_PYTHON_VERSION=3.12 and use the `--var-file` option to specify the file: ```bash -gh act --workflows .github/workflows/fast-checks.yaml --var-file=gh_vars.txt +gh act --workflows .github/workflows/check.yaml --var-file=gh_vars.txt ``` ### Running Workflows that use a Matrix Strategy @@ -80,7 +80,7 @@ gh act --workflows .github/workflows/fast-checks.yaml --var-file=gh_vars.txt This is optional, recent versions will automatically detect the matrix strategy and run supported values. To run a specific matrix item, use the `--matrix` option: ```bash -gh act --workflows .github/workflows/fast-checks.yaml --var-file=gh_vars.txt --matrix name:"Python Lint" +gh act --workflows .github/workflows/check.yaml --var-file=gh_vars.txt --matrix name:"Python Lint" ``` ### Running Release Workflows @@ -122,7 +122,7 @@ When running workflows that use `setup-uv` or similar setup actions, you may enc This happens because the container user doesn't have write access to `/opt/hostedtoolcache/`. Fix this by redirecting the tool cache to a writable location: ```bash -gh act --workflows .github/workflows/fast-checks.yaml \ +gh act --workflows .github/workflows/check.yaml \ -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest \ --env RUNNER_TOOL_CACHE=/tmp/tool_cache ``` diff --git a/docs/getting_started/code_standards.md b/docs/getting_started/code_standards.md index d56c0b3630f..08672b46e49 100644 --- a/docs/getting_started/code_standards.md +++ b/docs/getting_started/code_standards.md @@ -4,11 +4,11 @@ This document outlines the coding standards and practices used in the @ethereum/ ## Code and CI Requirements -Code pushed to @ethereum/execution-specs must fulfill the following checks in [CI](https://github.com/ethereum/execution-specs/actions/workflows/fast-checks.yaml): +Code pushed to @ethereum/execution-specs must fulfill the following checks in [CI](https://github.com/ethereum/execution-specs/actions/workflows/check.yaml): -| Type | Tox Command | Explanation | +| Type | Command | Explanation | | ---------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| **All fast checks** | `uvx tox -e fast-checks` | Run all fast static checks (lint, format, typecheck, spellcheck, etc.) in sequence. | +| **All static checks** | `just check` / `make check` / `uvx tox -e check`| Run all static checks (lint, format, typecheck, spellcheck, etc.) in sequence. | | Lint | `uvx tox -e lint` | Python lint check via `ruff`. | | Format | `uvx tox -e format` | Python code formatting check via `ruff`. | | Typecheck | `uvx tox -e typecheck` | Objects that provide typehints pass type-checking via `mypy`. | @@ -32,30 +32,27 @@ Code pushed to @ethereum/execution-specs must fulfill the following checks in [C !!! tip "Running checks easily" - Add an alias: + Run all static checks (recommended before pushing): ```console - alias tox="uvx tox" + just check # or: make check, uvx tox -e check ``` - Run all fast static checks (recommended before pushing): + Auto-fix lint and format issues: ```console - uvx tox -e fast-checks - ``` - - Run all checks in parallel: - - ```console - uvx tox run-parallel + just fix # or: make fix ``` Run specific checks: ```console - uvx tox -e lint,typecheck + just lint # or: uvx tox -e lint + just typecheck # or: uvx tox -e typecheck ``` + See [Build Tools](../dev/build_tools.md) for all available commands. + !!! info "Fix hints on failure" When a check fails, you'll see a **fix hint** with instructions on how to resolve the issue: @@ -79,7 +76,7 @@ Code pushed to @ethereum/execution-specs must fulfill the following checks in [C On the command-line, solve fixable issues with: ```console - uv run ruff check --fix + just fix # or: make fix ``` Use VS Code, see [VS Code Setup](../getting_started/setup_vs_code.md), to autoformat code, automatically organize Python module imports and highlight typechecking and spelling issues. diff --git a/docs/getting_started/code_standards_details.md b/docs/getting_started/code_standards_details.md index a68f973fe3b..5594f50283a 100644 --- a/docs/getting_started/code_standards_details.md +++ b/docs/getting_started/code_standards_details.md @@ -29,7 +29,7 @@ uvx tox -av Run all fast static checks before pushing (recommended): ```console -uvx tox -e fast-checks +uvx tox -e check ``` This runs lint, format, typecheck, spellcheck, spec-lint, lockcheck, actionlint, markdownlint, and changelog validation in sequence. On failure, each check provides a **fix hint** explaining how to resolve the issue. @@ -45,19 +45,19 @@ uvx tox -e lint,typecheck,spellcheck #### For Test Case Changes (`./tests/`) ```console -uvx tox -e fast-checks,py3 +uvx tox -e check,py3 ``` #### For Framework and Library Changes (`./src/`) ```console -uvx tox -e fast-checks,tests_pytest_py3 +uvx tox -e check,tests_pytest_py3 ``` #### For Documentation Changes (`./docs/`) ```console -uvx tox -e fast-checks,mkdocs +uvx tox -e check,mkdocs ``` !!! note "Tox Virtual Environment" diff --git a/docs/navigation.md b/docs/navigation.md index ec245156d9c..1ea3e65226b 100644 --- a/docs/navigation.md +++ b/docs/navigation.md @@ -75,6 +75,7 @@ * [Logging](dev/logging.md) * [Enabling Precommit Checks](dev/precommit.md) * [Running Github Actions Locally](dev/test_actions_locally.md) + * [Build Tools](dev/build_tools.md) * [Changelog](CHANGELOG.md) * [Library Reference](library/index.md) * [EEST CLI Tools](library/cli/index.md) From 6cc03857fe7622195dbcb7fbf8351f07ddea5179 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 10:09:10 +0100 Subject: [PATCH 09/12] feat(tooling): run checks in parallel for faster feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run all static checks in parallel via just/make for ~2x speedup (~6s → ~3s) and better error reporting (all checks run even if one fails). --- Justfile | 4 ++-- Makefile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Justfile b/Justfile index e33feeffc81..bc6a076feec 100644 --- a/Justfile +++ b/Justfile @@ -6,9 +6,9 @@ set quiet := true default: @just --list -# Static checks +# Static checks (parallel for speed) check: - uvx tox -e check + uvx tox --parallel -e lint,format,typecheck,spellcheck,spec-lint,lockcheck,actionlint,markdownlint,changelog lint: uvx tox -e lint diff --git a/Makefile b/Makefile index ab9812f25f7..4487c60ab4f 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-18s\033[0m %s\n", $$1, $$2}' -check: ## Run all static checks - uvx tox -e check +check: ## Run all static checks (parallel) + uvx tox --parallel -e lint,format,typecheck,spellcheck,spec-lint,lockcheck,actionlint,markdownlint,changelog lint: ## Python linting (ruff) uvx tox -e lint From b669a88f3ebc004f7fd8dbf35e2349ecc985bec6 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 10:46:57 +0100 Subject: [PATCH 10/12] oops broke ci --- packages/testing/src/execution_testing/fixtures/state.py | 5 +---- src/ethereum/forks/shanghai/fork.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/testing/src/execution_testing/fixtures/state.py b/packages/testing/src/execution_testing/fixtures/state.py index a69eb358996..d32688c0342 100644 --- a/packages/testing/src/execution_testing/fixtures/state.py +++ b/packages/testing/src/execution_testing/fixtures/state.py @@ -16,10 +16,7 @@ from execution_testing.exceptions import TransactionExceptionInstanceOrList from execution_testing.forks import Fork from execution_testing.test_types.block_types import EnvironmentGeneric -from execution_testing.test_types.transaction_types import ( - Transaction, - TransactionFixtureConverter, -) +from execution_testing.test_types.transaction_types import Transaction, TransactionFixtureConverter from .base import BaseFixture from .common import FixtureAuthorizationTuple, FixtureBlobSchedule diff --git a/src/ethereum/forks/shanghai/fork.py b/src/ethereum/forks/shanghai/fork.py index ce60d08f1f2..b0a503d6f6b 100644 --- a/src/ethereum/forks/shanghai/fork.py +++ b/src/ethereum/forks/shanghai/fork.py @@ -78,7 +78,7 @@ class BlockChain: chain_id: U64 -def apply_fork(old: BlockChain) -> BlockChain: +def apply_fork(old) -> BlockChain: """ Transforms the state from the previous hard fork (`old`) into the block chain object for this hard fork and returns it. From 38b593f9c76d58a0eac5bf9a8c72501083dc74c2 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 10:56:32 +0100 Subject: [PATCH 11/12] fix(ci): fix job summaries; render depends on check - Enable auto-fix hints to appear in CI job summaries by passing the GITHUB_STEP_SUMMARY env var through to tox environments. - fix(ci): don't double-wrap fix hints in code blocks. The fix_hint field already contains markdown code blocks, so write_github_summary shouldn't wrap it in another code block. - fix(ci): simplify verify hint to match PR template style. Show single line: just check # or: make check, uvx tox -e . - fix(ci): make render workflow depend on check workflow. --- .github/workflows/gh-pages.yaml | 4 ++++ scripts/fast_checks.py | 33 ++++++++++++--------------------- tox.ini | 1 + 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index c2a90f8f635..82935e92814 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -21,8 +21,12 @@ concurrency: cancel-in-progress: true jobs: + check: + uses: ./.github/workflows/check.yaml + build: name: "Build Documentation" + needs: check runs-on: "ubuntu-latest" steps: diff --git a/scripts/fast_checks.py b/scripts/fast_checks.py index dda6f17be27..7ae7cf516f3 100644 --- a/scripts/fast_checks.py +++ b/scripts/fast_checks.py @@ -35,34 +35,21 @@ class Check: run: Callable[[], int] # Function that runs the check, returns exit code -def write_github_summary(check: Check, check_key: str, output: str) -> None: +def write_github_summary(check: Check, check_key: str) -> None: """Write failure summary to GITHUB_STEP_SUMMARY if in CI.""" summary_file = os.environ.get("GITHUB_STEP_SUMMARY") if not summary_file: return - # Truncate output if too long - max_output = 2000 - if len(output) > max_output: - output = output[:max_output] + "\n... (truncated)" - with open(summary_file, "a") as f: f.write(f"## āŒ {check.name} failed\n\n") - f.write("```\n") - f.write(output) - f.write("\n```\n\n") + f.write("Expand the failed step above to see full output.\n\n") f.write("### How to fix\n\n") - f.write("```bash\n") f.write(check.fix_hint) - f.write("\n```\n\n") + f.write("\n\n") f.write("### How to verify\n\n") - f.write("Run the tool directly:\n\n") f.write("```bash\n") - f.write(check.verify_cmd) - f.write("\n```\n\n") - f.write("Or via tox:\n\n") - f.write("```bash\n") - f.write(f"tox -e {check_key}\n") + f.write(f"just check # or: make check, uvx tox -e {check_key}\n") f.write("```\n") @@ -72,7 +59,7 @@ def strip_markdown_code_blocks(text: str) -> str: return re.sub(r"```\w*\n?", "", text) -def print_fix_hint(check: Check) -> None: +def print_fix_hint(check: Check, check_key: str) -> None: """Print fix hint to stderr.""" sep = "=" * 60 hint = strip_markdown_code_blocks(check.fix_hint).strip() @@ -80,7 +67,11 @@ def print_fix_hint(check: Check) -> None: print(f"{check.name} failed:", file=sys.stderr) print(sep, file=sys.stderr) print(hint, file=sys.stderr) - print(f"\nVerify fix:\n{check.verify_cmd}", file=sys.stderr) + print("\nVerify fix:", file=sys.stderr) + print( + f"just check # or: make check, uvx tox -e {check_key}", + file=sys.stderr, + ) print(sep, file=sys.stderr) @@ -329,13 +320,13 @@ def main() -> None: exit_code = check.run() if exit_code != 0: - print_fix_hint(check) + print_fix_hint(check, args.check) # Only show aggregate hint when not running under tox if "TOX_ENV_NAME" not in os.environ: print("\nRun all static checks: tox -e check\n", file=sys.stderr) # For changelog, we already built the output message if args.check != "changelog": - write_github_summary(check, args.check, "See check output above") + write_github_summary(check, args.check) sys.exit(exit_code) diff --git a/tox.ini b/tox.ini index a8a5ea00eeb..6a02aa8695d 100644 --- a/tox.ini +++ b/tox.ini @@ -34,6 +34,7 @@ envlist = runner = uv-venv-lock-runner uv_seed = false wheel_build_env = .pkg +passenv = GITHUB_* # Individual static check environments (use scripts/fast_checks.py for fix hints) [testenv:spellcheck] From c309c56c61f030bb5ef2c7fc3a1dca5013fa2be2 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Jan 2026 11:26:39 +0100 Subject: [PATCH 12/12] Revert "oops broke ci" This reverts commit b669a88f3ebc004f7fd8dbf35e2349ecc985bec6. --- packages/testing/src/execution_testing/fixtures/state.py | 5 ++++- src/ethereum/forks/shanghai/fork.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/testing/src/execution_testing/fixtures/state.py b/packages/testing/src/execution_testing/fixtures/state.py index d32688c0342..a69eb358996 100644 --- a/packages/testing/src/execution_testing/fixtures/state.py +++ b/packages/testing/src/execution_testing/fixtures/state.py @@ -16,7 +16,10 @@ from execution_testing.exceptions import TransactionExceptionInstanceOrList from execution_testing.forks import Fork from execution_testing.test_types.block_types import EnvironmentGeneric -from execution_testing.test_types.transaction_types import Transaction, TransactionFixtureConverter +from execution_testing.test_types.transaction_types import ( + Transaction, + TransactionFixtureConverter, +) from .base import BaseFixture from .common import FixtureAuthorizationTuple, FixtureBlobSchedule diff --git a/src/ethereum/forks/shanghai/fork.py b/src/ethereum/forks/shanghai/fork.py index b0a503d6f6b..ce60d08f1f2 100644 --- a/src/ethereum/forks/shanghai/fork.py +++ b/src/ethereum/forks/shanghai/fork.py @@ -78,7 +78,7 @@ class BlockChain: chain_id: U64 -def apply_fork(old) -> BlockChain: +def apply_fork(old: BlockChain) -> BlockChain: """ Transforms the state from the previous hard fork (`old`) into the block chain object for this hard fork and returns it.