Implementation:SeleniumHQ Selenium Format Sh Script
| Knowledge Sources | |
|---|---|
| Domains | Code_Quality, Continuous_Integration, Developer_Experience |
| Last Updated | 2026-02-11 00:00 GMT |
Overview
Concrete tool for automated multi-language code formatting provided by the scripts/format.sh script.
Description
format.sh is a Bash script (with set -eufo pipefail for strict error handling) that formats changed files using language-specific formatters. It supports four modes: default (all changes vs trunk including uncommitted work), --pre-commit (staged only via git diff --cached), --pre-push (committed vs trunk via git diff base..HEAD), and --all (everything, skipping change detection). The --lint flag adds linter checks (Python ruff check, Shell actionlint + shellcheck). Modes --pre-commit and --pre-push are mutually exclusive.
The script uses bazel info workspace to determine the workspace root and delegates formatting to Bazel-managed tools. It captures a baseline via git status --porcelain before formatting and compares afterward; if the porcelain output differs, it exits with code 1 and prints the names of modified files.
Usage
Run before committing or pushing. CI will fail if formatting changes are needed.
Code Reference
Source Location
- Repository: Selenium
- File: scripts/format.sh (L1-148)
Signature
./scripts/format.sh [OPTIONS]
Options:
--all Format all files (skip change detection)
--pre-commit Format only staged changes (git diff --cached)
--pre-push Format committed changes vs trunk (git diff base..HEAD)
--lint Run linters in addition to formatters
(default) All changes relative to trunk including uncommitted work
Key Implementation Details
#!/usr/bin/env bash
set -eufo pipefail
# Change detection uses git merge-base to find common ancestor with trunk
trunk_ref="$(git rev-parse --verify trunk 2>/dev/null || echo "")"
base="$(git merge-base HEAD "$trunk_ref" 2>/dev/null || echo "")"
# Default mode combines: committed + staged + unstaged + untracked
committed="$(git diff --name-only "$base" HEAD)"
staged="$(git diff --name-only --cached)"
unstaged="$(git diff --name-only)"
untracked="$(git ls-files --others --exclude-standard)"
changed="$(printf '%s\n%s\n%s\n%s' "$committed" "$staged" "$unstaged" "$untracked" | sort -u)"
# Helper checks if pattern matches changed files (or if --all)
changed_matches() {
[[ "$format_all" == "true" ]] || echo "$changed" | grep -qE "$1"
}
# Always run buildifier and copyright
bazel run //:buildifier
bazel run //scripts:update_copyright
# Conditionally run per language:
# Java: google-java-format --replace (find *.java in java/)
# JavaScript: prettier --write
# Ruby: rubocop -a (--fail-level F without --lint)
# Rust: @rules_rust//:rustfmt
# Python: ruff check (if --lint) + ruff format
# .NET: dotnet format style --severity warn + whitespace
# Shell/CI: actionlint with shellcheck (if --lint)
# Compare baseline to detect formatter changes
baseline="$(git status --porcelain)"
# ... after formatting ...
if [[ "$(git status --porcelain)" != "$baseline" ]]; then
exit 1
fi
Import
N/A - Shell script
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| --all | Flag | No | Format everything, skip change detection |
| --pre-commit | Flag | No | Format staged changes only (mutually exclusive with --pre-push) |
| --pre-push | Flag | No | Format committed changes vs trunk (mutually exclusive with --pre-commit) |
| --lint | Flag | No | Also run linters (ruff check, actionlint, shellcheck) |
Outputs
| Name | Type | Description |
|---|---|---|
| Formatted files | Modified files | Source files reformatted in-place |
| Exit code | int | 0 = no changes needed (format check passed), 1 = files were modified by formatters |
Formatter-to-Language Mapping
| File Pattern | Formatter | Bazel Target |
|---|---|---|
^java/ |
google-java-format | //scripts:google-java-format
|
^javascript/selenium-webdriver/ |
prettier | //javascript:prettier
|
^rb/, ^rake_tasks/, ^Rakefile |
rubocop -a | //rb:rubocop
|
^rust/ |
rustfmt | @rules_rust//:rustfmt
|
^py/ |
ruff format (+ ruff check) | //py:ruff-format, //py:ruff-check
|
^dotnet/ |
dotnet format | //dotnet:format
|
| (always) | buildifier | //:buildifier
|
| (always) | update_copyright | //scripts:update_copyright
|
| (--lint only) | actionlint + shellcheck | @multitool//tools/actionlint:cwd, @multitool//tools/shellcheck
|
Usage Examples
Before Committing
# Format all changes relative to trunk (default mode)
./scripts/format.sh
# Format only staged files (for pre-commit hook)
./scripts/format.sh --pre-commit
Full Format and Lint
# Format and lint everything
./scripts/format.sh --all --lint
Via ./go Wrapper
# Alternative: use the Rake wrapper
./go all:lint
CI Integration
# In CI, check if formatting is needed (exits 1 if changes detected)
./scripts/format.sh --pre-push
if [ $? -ne 0 ]; then
echo "Formatting check failed. Run ./scripts/format.sh locally."
exit 1
fi