### Install jj-pre-push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Install jj-pre-push using pip, uv, or pipx. For temporary use without installation, use uvx. ```bash # Via pip pip install jj-pre-push # Via uv uv tool install jj-pre-push # Via pipx pipx install jj-pre-push # Via uvx (temporary, no installation) uvx jj-pre-push push ``` -------------------------------- ### Callback Usage Example Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Demonstrates how to invoke the jj-pre-push CLI with a specific log level using command-line arguments or environment variables. ```bash # The callback is invoked automatically by Typer. # To use with a specific log level: # Command line: jj-pre-push --log-level=DEBUG push # Or environment variable: JJ_PRE_PUSH_LOG_LEVEL=DEBUG jj-pre-push push ``` -------------------------------- ### Install jj-pre-push using pipx Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Install jj-pre-push using pipx, which installs Python applications in isolated environments. This is useful for command-line tools. ```bash pipx install jj-pre-push ``` -------------------------------- ### Entry Point Configuration Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/README.md This configuration specifies the entry point for the jj-pre-push tool when installed via PyPI. It invokes the Typer CLI application. ```toml jj-pre-push = "jj_pre_push.cli:app" ``` -------------------------------- ### JJ-Pre-Push Version Callback Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Eager callback for the --version option. Prints the installed version of jj-pre-push and exits. ```python def version_callback(value: bool) -> None: pass ``` ```shell # Invoked via CLI: # jj-pre-push --version # Output: jj-pre-push version 0.5.0 ``` -------------------------------- ### CLI Usage Examples for 'push' Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Demonstrates how to use the 'push' command from the CLI, including basic invocation, requesting help for 'jj git push', and performing a dry run. ```bash # Invoked via CLI: # jj-pre-push push origin main # With help: # jj-pre-push push --help # With dry-run: # jj-pre-push push --dry-run origin main ``` -------------------------------- ### Install jj-pre-push using pip Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Install jj-pre-push using pip, the standard Python package installer. This command installs the package and its dependencies. ```bash pip install jj-pre-push ``` -------------------------------- ### Pre-commit Config for Hooks on Push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Example configuration for .pre-commit-config.yaml to enable hooks like black and ruff specifically for the push stage. ```yaml repos: - repo: https://github.com/psf/black rev: 23.3.0 hooks: - id: black stages: [push] # Enable for pre-push - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.0.262 hooks: - id: ruff stages: [push] ``` -------------------------------- ### version_callback Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Eager callback for the --version option. Prints the installed version of jj-pre-push and exits. ```APIDOC ## version_callback ### Description Eager callback for the `--version` option. Prints the installed version of jj-pre-push and exits. ### Method N/A (Callback function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **value** (bool) - Required - Always True when invoked (condition for eager callback) ### Response #### Success Response None (Exits gracefully) ### Example ```bash # Invoked via CLI: # jj-pre-push --version # Output: # jj-pre-push version 0.5.0 ``` ``` -------------------------------- ### Getting Current Change Summary Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Example of how to retrieve the current change summary using the current_change() function and print its details. ```python change = current_change() print(f"Current change: {change.change_id} (empty={change.empty})") ``` -------------------------------- ### Install jj-pre-push using uv Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Install jj-pre-push using uv, a fast Python package installer and resolver. This command is an alternative to pip for managing Python packages. ```bash uv tool install jj-pre-push ``` -------------------------------- ### Get Remote Bookmark Updates and Workspace Info Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md This snippet demonstrates how to use jj-pre-push functions to retrieve information about remote bookmark updates, the current working commit, and the workspace root. Ensure jj-pre-push is installed and accessible in your Python environment. ```python from jj_pre_push.bookmark_updates import get_remote_bookmark_updates from jj_pre_push.jj import workspace_root, current_change # Get what will be pushed updates = get_remote_bookmark_updates(["origin", "main"]) print(f"Will push {len(updates)} bookmarks:") for update in updates: print(f" {update}") # Get current working commit change = current_change() print(f"Working commit: {change.change_id}") print(f"Is empty: {change.empty}") # Get workspace root root = workspace_root() print(f"Workspace root: {root}") ``` -------------------------------- ### Python Examples for 'checker_command' Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Illustrates the output of the 'checker_command' function for different checker names, showing the generated command lists for subprocess execution. ```python checker_command("pre-commit") # Returns ["pre-commit", "run", "--hook-stage", "pre-push"] checker_command("hk") # Returns ["hk", "run", "pre-push"] checker_command("prek") # Returns ["prek", "run", "--hook-stage", "pre-push"] ``` -------------------------------- ### jj configuration for push alias with uvx Source: https://github.com/acarapetis/jj-pre-push/blob/main/README.md Configure jj aliases to use uvx for executing jj-pre-push. This avoids explicit installation if uv is present. ```toml [aliases] push = ["util", "exec", "--", "uvx", "jj-pre-push", "push"] ``` -------------------------------- ### Using jj Push with jj-pre-push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Examples of how to use the `jj push` command after configuring the alias. These commands will trigger jj-pre-push checks before executing the push operation. ```bash jj push # Runs all checks and pushes to default remote ``` ```bash jj push origin main # Runs all checks and pushes main to origin ``` ```bash jj push -r some_bookmark # Runs checks on some_bookmark and pushes it ``` -------------------------------- ### CLI Usage Example for 'check' Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Shows how to invoke the 'check' command from the command line, typically with a remote and branch name. It can also be called internally by the 'push' command. ```bash # Typically invoked via CLI: # jj-pre-push check origin main # Or via the push command (which calls check internally): # jj-pre-push push origin main ``` -------------------------------- ### Get Bookmark Updates Failure Flow Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Details the error handling when `get_remote_bookmark_updates()` fails. ```text get_remote_bookmark_updates() -> JJError ↓ cli.check() catches JJError ↓ Logs error message, raises typer.Exit(returncode) ``` -------------------------------- ### Get Current Working State Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Obtain the current change information for the working copy. This is useful for understanding the state of the repository before a push. ```python from jj_pre_push.jj import current_change change = current_change() ``` -------------------------------- ### Global Callback Function Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md The `callback` function is a global Typer callback executed before any subcommand. It handles logging setup and context object creation. ```APIDOC ## Functions ### callback ```python def callback( ctx: typer.Context, log_level: Annotated[str, typer.Option(envvar="JJ_PRE_PUSH_LOG_LEVEL")] = "WARNING", checker: Annotated[str, typer.Option(envvar="JJ_PRE_PUSH_CHECKER", help="Executable to call to run checks (e.g. prek)")] = "pre-commit", mode: Annotated[Mode, typer.Option(envvar="JJ_PRE_PUSH_MODE", help="EXPERIMENTAL: Determines which files to check. default: use pre-commit's default logic for pre-push hooks. remote-ancestors: files changed since the most recent ancestors already present on the remote.")] = "default", version: Annotated[bool, typer.Option("--version", callback=version_callback, is_eager=True, help="Show version and exit.")] = False, ) -> None ``` Global callback executed before any subcommand. Sets up logging and creates the Settings object attached to the Typer context. **Parameters:** | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `ctx` | `typer.Context` | Yes | — | Typer context object for storing application state | | `log_level` | `str` | No | "WARNING" | Logging level name. Accepts environment variable `JJ_PRE_PUSH_LOG_LEVEL`. Valid values: DEBUG, INFO, WARNING, ERROR, CRITICAL | | `checker` | `str` | No | "pre-commit" | Name of the hook checker executable to use. Accepts environment variable `JJ_PRE_PUSH_CHECKER`. Supported values: "pre-commit", "prek", "hk" | | `mode` | `Mode` | No | "default" | File selection strategy for checks. Accepts environment variable `JJ_PRE_PUSH_MODE` | | `version` | `bool` | No | False | If True, prints version and exits (eager option) | **Side Effects:** - Configures logging with format "jj-pre-push: %(message)s" at the specified level - Sets `ctx.obj` to a Settings instance with the given checker and mode values **Return Type:** `None` **Example:** ```python # The callback is invoked automatically by Typer. # To use with a specific log level: # Command line: jj-pre-push --log-level=DEBUG push # Or environment variable: JJ_PRE_PUSH_LOG_LEVEL=DEBUG jj-pre-push push ``` ``` -------------------------------- ### Handling JJError Exception Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Example of how to catch and handle a JJError exception when executing a jj command. It prints the return code and message from the exception. ```python try: output = jj(["log"]) except JJError as e: print(f"jj exited with code {e.returncode}: {e.message}") ``` -------------------------------- ### Typical Workflow for jj-pre-push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/README.md Illustrates the sequence of operations when using jj-pre-push to push changes. It shows the detection of bookmarks, execution of pre-push hooks, and the final push action. ```text jj-pre-push push origin main ↓ [detect bookmarks that will be pushed] ↓ [for each bookmark: run pre-push hooks] ↓ [if all pass: execute jj git push] [if any fail: report errors, don't push] ``` -------------------------------- ### jj-pre-push CLI Entry Point Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md The main entry point for the jj-pre-push CLI is defined in pyproject.toml, allowing users to invoke the tool directly. ```APIDOC ## CLI Module Overview The CLI module provides the command-line interface for jj-pre-push, exposing commands like `check` and `push`. ### Command Entry Point The module is invoked via the entry point `jj-pre-push = "jj_pre_push.cli:app"` as defined in pyproject.toml. ``` -------------------------------- ### jj-pre-push Command Structure Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Illustrates the basic command structure for jj-pre-push, including global options, available commands, and how arguments are passed through to jj git push. ```bash jj-pre-push [GLOBAL_OPTIONS] COMMAND [COMMAND_OPTIONS] [ARGS]... GLOBAL_OPTIONS: --log-level (default: WARNING) --checker (default: pre-commit) --mode (default: default) --version (eager flag) COMMANDS: push Run checks + execute jj git push check Run checks only (dry-run verification) help Show help PASS-THROUGH: [ARGS]... are forwarded to jj git push ``` -------------------------------- ### Basic jj-pre-push Usage Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Run checks and push, perform a dry run to see what would be pushed, or run checks only. Also shows how to display version and help information. ```bash # Run checks and push if all pass jj-pre-push push origin main # Dry run: see what would be pushed without actually pushing jj-pre-push push --dry-run origin main # Run checks only (don't push) jj-pre-push check origin main # Show version jj-pre-push --version # Show help jj-pre-push --help jj-pre-push push --help ``` -------------------------------- ### Print Version Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Use the --version flag to display the current version of jj-pre-push and exit the program. ```bash jj-pre-push --version ``` -------------------------------- ### Get Workspace Root Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Determine the root directory of the current jj workspace. This function is part of the jj module and can be used for path-related operations. ```python from jj_pre_push.jj import workspace_root root = workspace_root() ``` -------------------------------- ### Get Remote Bookmark Updates Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Retrieve a list of bookmark updates that will be pushed to the specified remote and branch. This function is part of the bookmark_updates module. ```python from jj_pre_push.bookmark_updates import get_remote_bookmark_updates updates = get_remote_bookmark_updates(["origin", "main"]) ``` -------------------------------- ### jj-pre-push Module Structure Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Illustrates the directory structure of the jj-pre-push package and the files within it. ```tree jj_pre_push/ ├── __init__.py [empty] ├── cli.py [274 lines] → api-reference/cli.md ├── jj.py [104 lines] → api-reference/jj.md └── bookmark_updates.py [95 lines] → api-reference/bookmark-updates.md ``` -------------------------------- ### Show Help for jj git push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Use the --help flag to display help information specific to the `jj git push` command. This is useful for understanding available push-related options. ```bash jj-pre-push push --help ``` -------------------------------- ### Configure jj Alias for Push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Set up a jj alias to use jj-pre-push as the default push command. This allows you to use `jj push` as usual, with jj-pre-push running checks before the actual push. ```toml [aliases] push = ["util", "exec", "--", "jj-pre-push", "push"] ``` -------------------------------- ### Configure jjui Integration for Push Action Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Set up jjui configuration to trigger the 'jj-push' action using Lua scripting. This action is designed to call jj-pre-push. ```toml [[actions]] name = "jj-push" lua = ''' jj_async("push") revisions.refresh() ''' ``` -------------------------------- ### Checker Integration CLI Formats Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Shows the command-line formats for integrating different checkers with jj-pre-push, highlighting variations in argument support. ```bash pre-commit run --hook-stage pre-push --from-ref X --to-ref Y ``` ```bash prek run --hook-stage pre-push --from-ref X --to-ref Y ``` ```bash hk run pre-push ``` ```bash {checker} run --hook-stage pre-push --from-ref X --to-ref Y ``` -------------------------------- ### Get Current Change Summary Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Fetches information about the current working copy commit. It returns a `ChangeSummary` object, which includes details like the change ID and whether the commit is empty. ```python def current_change() -> ChangeSummary ``` ```python change = current_change() if change.empty: print(f"Working commit {change.change_id} is empty") else: print(f"Working commit {change.change_id} contains modifications") ``` -------------------------------- ### Module Architecture Overview Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md This snippet shows the directory structure and module responsibilities within the jj-pre-push project. ```tree jj_pre_push/ ├── __init__.py (empty) ├── cli.py (entry point, command definitions) ├── jj.py (jj CLI wrapper and utilities) └── bookmark_updates.py (bookmark change detection and parsing) ``` -------------------------------- ### jj-pre-push Push Command Execution Flow Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Illustrates the sequence of operations when the 'jj-pre-push push' command is invoked, including checks and Git integration. ```text User invokes: jj-pre-push push [args] │ ├─→ cli.push(ctx, help, dry_run) │ ├─→ cli.check(ctx) [if not help] │ │ ├─→ jj.workspace_root() [get repo root] │ │ │ ├─→ [if .pre-commit-config.yaml exists] │ │ │ │ ├─→ bookmark_updates.get_remote_bookmark_updates(args) │ │ │ ├─→ jj.jj(["git", "push", "--dry-run", ...]) │ │ │ └─→ bookmark_updates.parse_git_push_dry_run(output) │ │ │ └─→ returns: set[BookmarkUpdate] │ │ │ │ │ ├─→ [filter to non-delete updates] │ │ │ │ │ ├─→ jj.autostash() [context manager] │ │ │ │ │ │ For each BookmarkUpdate: │ │ │ ├─→ Determine "from" commit reference(s) │ │ │ ├─→ jj.edit() or jj.new() to check out bookmark/create temp commit │ │ │ ├─→ subprocess.run([checker_command(...)], ...) │ │ │ ├─→ Log result (success or failure) │ │ │ │ │ └─→ [end autostash: restore original working copy] │ │ │ └─→ [if all checks passed: return normally] │ [else: raise typer.Exit(1)] │ ├─→ [if not check failed] subprocess.run(["jj", "git", "push", ...], check=True) │ └─→ Exit with code 0 or 1 ``` -------------------------------- ### Get JJ Workspace Root Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Retrieves the root directory of the current JJ workspace. This function is designed to avoid side effects by not snapshotting the working copy. It returns a `Path` object. ```python def workspace_root() -> Path ``` ```python from pathlib import Path root = workspace_root() config_file = root / ".pre-commit-config.yaml" if config_file.exists(): print(f"Found pre-commit config at {config_file}") ``` -------------------------------- ### Create New Working Copy Commit Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Creates a new commit as a child of the current working commit or a specified revision. Use when you need to start a new line of work or branch off from a specific point. ```python def new(ref: str | None = None) -> None ``` ```python # Create a new commit on top of the current revision new() # Create a new commit as a child of a specific revision new("main") ``` -------------------------------- ### Enable Debug Mode and Dry Run Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Run jj-pre-push with DEBUG log level and a dry-run option to inspect behavior without making actual changes. Useful for troubleshooting. ```bash jj-pre-push --log-level=DEBUG push --dry-run origin main ``` -------------------------------- ### Set Mode via Command-Line Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Use the --mode option to control which files are checked when running pre-push hooks on bookmarks. The 'remote-ancestors' mode is experimental. ```bash jj-pre-push --mode=remote-ancestors push origin main ``` -------------------------------- ### Global Callback Function Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md The main callback executed before any subcommand. It sets up logging and initializes the Settings object in the Typer context. ```python def callback( ctx: typer.Context, log_level: Annotated[str, typer.Option(envvar="JJ_PRE_PUSH_LOG_LEVEL")] = "WARNING", checker: Annotated[str, typer.Option(envvar="JJ_PRE_PUSH_CHECKER", help="Executable to call to run checks (e.g. prek)")] = "pre-commit", mode: Annotated[Mode, typer.Option(envvar="JJ_PRE_PUSH_MODE", help="EXPERIMENTAL: Determines which files to check. default: use pre-commit's default logic for pre-push hooks. remote-ancestors: files changed since the most recent ancestors already present on the remote.")] = "default", version: Annotated[bool, typer.Option("--version", callback=version_callback, is_eager=True, help="Show version and exit.")] = False, ) -> None: # ... implementation details ... ``` -------------------------------- ### Configure jj-pre-push Logging and Checker via Environment Variables Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Customize logging level and the hook checker executable using environment variables. This allows for persistent configuration across multiple commands. ```bash export JJ_PRE_PUSH_LOG_LEVEL=DEBUG export JJ_PRE_PUSH_CHECKER=hk export JJ_PRE_PUSH_MODE=remote-ancestors jj-pre-push push origin main ``` -------------------------------- ### jj-pre-push with Alternative Checker Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Use a different hook checker, such as 'hk', by specifying it with the --checker option. This allows flexibility in choosing the pre-push hook mechanism. ```bash # Use alternative checker jj-pre-push --checker=hk push origin main ``` -------------------------------- ### Troubleshooting jj-pre-push Commands Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Use these commands for debugging and verifying actions without performing a push. The DEBUG log level provides detailed logging, while --dry-run and check verify actions without pushing. ```bash # Debug mode: see detailed logging jj-pre-push --log-level=DEBUG push origin main ``` ```bash # Dry-run: verify what would be checked without pushing jj-pre-push push --dry-run origin main ``` ```bash # Check only: verify checks pass without pushing jj-pre-push check origin main ``` -------------------------------- ### Run Checks and Push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Execute pre-push checks and then push to the specified remote and branch. Use this for a standard push operation. ```bash jj-pre-push push origin main ``` -------------------------------- ### Push Specific Bookmarks with jj-pre-push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md When pushing, specify the target remote and bookmark to push instead of pushing all. This can improve performance by reducing the scope of the push operation. ```bash jj-pre-push push origin main # Only main ``` -------------------------------- ### Generated Documentation File Structure Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Lists the locations of all generated documentation files within the output directory. This provides an overview of where to find specific information. ```bash output/ ├── INDEX.md [this file] ├── quick-reference.md [quick lookup] ├── configuration.md [CLI options, env vars] ├── types.md [type system reference] ├── errors.md [error catalog] ├── architecture.md [design and implementation] └── api-reference/ ├── cli.md [CLI module] ├── jj.md [jj wrapper module] └── bookmark-updates.md [bookmark parsing module] ``` -------------------------------- ### jj-pre-push Push with Revision Specification Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Push using a revision specification, such as 'my-bookmark', with the -r flag. This enables pushing based on specific commit references. ```bash # Push with revision specification jj-pre-push push -r 'my-bookmark' ``` -------------------------------- ### jj-pre-push with Detailed Logging Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Execute the check command with detailed logging enabled by setting the log level to DEBUG. This is useful for troubleshooting. ```bash # Check with detailed logging jj-pre-push --log-level=DEBUG check origin main ``` -------------------------------- ### jj-pre-push with Environment Variable Checker Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Set the checker to 'prek' by exporting the JJ_PRE_PUSH_CHECKER environment variable. This method is an alternative to using the CLI option. ```bash # Set environment variable instead export JJ_PRE_PUSH_CHECKER=prek jj-pre-push push origin main ``` -------------------------------- ### External Pre-commit Configuration Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Define pre-push hooks using a standard .pre-commit-config.yaml file. This file specifies repositories and hooks that jj-pre-push will execute. If this file is absent, jj-pre-push bypasses checks and directly uses `jj git push`. ```yaml repos: - repo: https://github.com/psf/black rev: 23.3.0 hooks: - id: black stages: [commit, push] # Enable for pre-push hooks - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.0.262 hooks: - id: ruff stages: [commit, push] ``` -------------------------------- ### jjui custom actions for jj-push Source: https://github.com/acarapetis/jj-pre-push/blob/main/README.md Define custom actions in jjui to trigger jj-pre-push for default push and selected bookmarks. Requires the 'jj push' alias. ```lua [[actions]] name = "jj-push" lua = ''' jj_async("push") revisions.refresh() ''' [[actions]] name = "jj-push-selected" lua = ''' jj_async("push", "-r", context.commit_id()) revisions.refresh() ''' ``` -------------------------------- ### Push Specific Bookmarks with Verbose Output Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Pass additional arguments to `jj git push` to specify which bookmarks to push and enable verbose output. This allows for fine-grained control over the push operation. ```bash jj-pre-push push origin main -v ``` -------------------------------- ### Push with Custom Checker Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/INDEX.md Execute pre-push checks using a custom checker, such as 'hk', before pushing to the remote. This allows integration with alternative checking tools. ```bash jj-pre-push --checker=hk push origin main ``` -------------------------------- ### Define Custom jj Alias for Pre-Push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Configure a custom 'push' alias in .jj/config.toml that includes environment variable settings for jj-pre-push. This simplifies running pre-push checks with specific configurations. ```toml [aliases] push = ["util", "exec", "--", "bash", "-c", "export JJ_PRE_PUSH_LOG_LEVEL=INFO && jj-pre-push push"] ``` -------------------------------- ### Settings Configuration Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md The Settings dataclass holds configuration parameters for the CLI, including checker executable and file selection mode. ```APIDOC ## Settings ```python @dataclass class Settings: checker: str mode: Mode ``` Configuration container passed through the Typer context to subcommands. **Fields:** | Field | Type | Description | |-------|------|-------------| | `checker` | `str` | Executable to invoke for running checks (e.g., "pre-commit", "hk", "prek"). Configurable via `--checker` option or `JJ_PRE_PUSH_CHECKER` environment variable. Defaults to "pre-commit". | | `mode` | `Mode` | File selection mode for checks. Type is `Literal["default", "remote-ancestors"]`. Configurable via `--mode` option or `JJ_PRE_PUSH_MODE` environment variable. Defaults to "default". | ``` -------------------------------- ### check Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Determines which bookmarks will be pushed and runs pre-push hooks on each. This is the core operation; `push` calls `check` before delegating to `jj git push`. ```APIDOC ## check ### Description Determines which bookmarks will be pushed and runs pre-push hooks on each. This is the core operation; `push` calls `check` before delegating to `jj git push`. ### Method Not applicable (CLI command) ### Endpoint Not applicable (CLI command) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **ctx** (`typer.Context`) - Required - Typer context containing Settings in `ctx.obj` and `jj git push` arguments in `ctx.args` ### Behavior: 1. Retrieves workspace root via `jj.workspace_root()`. Exits with error if not in a jj workspace. 2. If no `.pre-commit-config.yaml` exists in the workspace root, logs that there is nothing to check and returns immediately. 3. Calls `get_remote_bookmark_updates(ctx.args)` to determine which bookmarks will be updated by the push operation. Exits with error if this fails. 4. Filters the updates to exclude bookmark deletions. 5. Iterates through each remaining bookmark update: - Determines the "from" commit reference(s) based on the mode and whether the bookmark is new or existing - If the current working commit is empty and is a direct child of the bookmark being pushed, reuses the working commit; otherwise creates a new one with `jj new()` - Runs the checker via subprocess with `--from-ref` and `--to-ref` arguments - Logs errors if the checker returns non-zero exit code; also checks if the checker modified files 6. After all updates are checked, restores the original working copy via the `autostash()` context manager. 7. If all checkers succeeded, logs "All checks passed." and returns normally. Otherwise logs "One or more checks failed, please fix before pushing." and raises `typer.Exit(1)`. ### Throws: - `typer.Exit(returncode)`: If `jj.workspace_root()` or `get_remote_bookmark_updates()` raises `jj.JJError` - `typer.Exit(1)`: If any checker command returns non-zero exit code ### Return Type: `None` ### Example: ```python # Typically invoked via CLI: # jj-pre-push check origin main # Or via the push command (which calls check internally): # jj-pre-push push origin main ``` ``` -------------------------------- ### Settings Data Class Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Defines the configuration structure for jj-pre-push, holding checker and mode settings. ```python from dataclasses import dataclass @dataclass class Settings: checker: str mode: Mode ``` -------------------------------- ### jj-pre-push Dry Run Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Perform a dry run of the push operation to preview changes without actually pushing them. This is useful for verification. ```bash # Push with dry-run (don't actually push) jj-pre-push push --dry-run origin main ``` -------------------------------- ### Bind jjui Action to Keyboard Shortcut Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Define a keyboard binding in jjui's config.toml to execute the 'jj-push' action when 'xp' is pressed in the revisions scope. This allows for quick triggering of pre-push checks from jjui. ```toml [[bindings]] action = "jj-push" seq = ["x", "p"] scope = "revisions" desc = "jj push" ``` -------------------------------- ### push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/cli.md Executes `check()` and then delegates to `jj git push` with the provided arguments. ```APIDOC ## push ### Description Executes `check()` and then delegates to `jj git push` with the provided arguments. ### Method Not applicable (CLI command) ### Endpoint Not applicable (CLI command) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters: - **ctx** (`typer.Context`) - Required - Typer context containing Settings and push arguments in `ctx.args` - **help** (`bool`) - Optional - Default: `False` - If True, shows help for `jj git push` instead of running checks - **dry_run** (`bool`) - Optional - Default: `False` - If True, appends `--dry-run` to the push arguments ### Behavior: 1. If `help=True`, runs `jj git push --help` with any additional arguments and returns. 2. Calls `check(ctx)` to run all pre-push hooks. If this raises `typer.Exit(1)`, the exception propagates and the function exits without pushing. 3. If `dry_run=True`, appends `--dry-run` to the push arguments. 4. Executes `jj git push` with all arguments via `subprocess.run(..., check=True)`. ### Throws: - `typer.Exit(1)`: If `check()` fails (hook execution failure) - `subprocess.CalledProcessError`: If `jj git push` exits with non-zero code and `check=True` is set (will raise to caller) ### Return Type: `None` ### Example: ```python # Invoked via CLI: # jj-pre-push push origin main # With help: # jj-pre-push push --help # With dry-run: # jj-pre-push push --dry-run origin main ``` ``` -------------------------------- ### parse_git_push_dry_run Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/bookmark-updates.md Parses the standard output of `jj git push --dry-run` to extract a set of bookmark updates. It supports both current and older JJ version output formats for various update types like moving, adding, or deleting bookmarks. ```APIDOC ## parse_git_push_dry_run ### Description Parses the stdout of `jj git push --dry-run` and extracts bookmark update details. This function is crucial for understanding the potential impact of a push operation on remote bookmarks without actually performing the push. ### Method Signature ```python def parse_git_push_dry_run(output: str) -> set[BookmarkUpdate] ``` ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Parameters - **output** (`str`) - Required - The complete stdout from `jj git push --dry-run`. ### Return Type `set[BookmarkUpdate]` - A set of BookmarkUpdate objects, one per update reported by jj. Returns an empty set if no updates are reported. ### Throws - **ValueError**: If a bookmark update line is encountered before any "Changes to push to REMOTE:" line, indicating unexpected line ordering in the output. ### Behavior - Splits the output into lines and tracks the current remote name. - Uses regex patterns to match each of the five update types (`move_forward`, `move_backward`, `move_sideways`, `add`, `delete`), supporting both current and legacy output formats. - Constructs and returns a set of `BookmarkUpdate` objects for each matched update. ### Regex Patterns Supported **move_forward:** - Current: `Move forward bookmark {name} from {old} to {new}` - Compact: `bookmark: {name} [move forward from {old} to {new}]` **move_backward:** - Current: `Move backward bookmark {name} from {old} to {new}` - Compact: `bookmark: {name} [move backward from {old} to {new}]` **move_sideways:** - Current: `Move sideways bookmark {name} from {old} to {new}` - Compact: `bookmark: {name} [move sideways from {old} to {new}]` **add:** - Current: `Add bookmark {name} to {new}` - Compact: `bookmark: {name} [add to {new}]` **delete:** - Current: `Delete bookmark {name} from {old}` - Compact: `bookmark: {name} [delete from {old}]` ### Example ```python output = """ Changes to push to origin: bookmark: main [move forward from d964e724c76e to a81d749233ff] bookmark: feature [add to 591f7e9aae85] Dry-run requested, not pushing. """ updates = parse_git_push_dry_run(output) # updates will be a set containing: # BookmarkUpdate("origin", "main", "move_forward", "d964e724c76e", "a81d749233ff") # BookmarkUpdate("origin", "feature", "add", None, "591f7e9aae85") ``` ``` -------------------------------- ### jj Config Alias for Push Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/quick-reference.md Configure an alias in jj's config to streamline the execution of jj-pre-push as part of the push command. ```toml [aliases] push = ["util", "exec", "--", "jj-pre-push", "push"] ``` -------------------------------- ### Workspace Root Failure Flow Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Details the error handling when the `jj.workspace_root()` function fails. ```text workspace_root() -> JJError ↓ cli.check() catches JJError ↓ Logs error message, raises typer.Exit(returncode) ``` -------------------------------- ### jj Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Executes a jj CLI command and captures its output. This is the core interface for invoking jj. ```APIDOC ## jj ### Description Executes a `jj` CLI command and captures its output. This is the core interface for invoking jj. ### Method `jj` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - `args` (list[str]) - Required - Command arguments (without the "jj" prefix). Example: `["log", "-r", "@"]` becomes `jj log -r @` - `snapshot` (bool) - Optional - If False, appends `--ignore-working-copy` to the command. Default: `True` - `suppress_stderr` (bool) - Optional - If True, redirects stderr to a pipe (still captured but not shown to user). Default: `False` - `capture_stderr` (bool) - Optional - If True, redirects stderr to stdout (merged into return value). Default: `False` - `color` (Literal["always", "never", "debug", "auto"] | None) - Optional - Color output mode. If None, does not add `--color` flag. Default: `"never"` ### Return Type `str` — The captured stdout from the jj command, with leading/trailing whitespace stripped. ### Throws - `JJError` - If the jj subprocess exits with non-zero code. The exception contains the stdout and return code. ### Behavior - Builds the command as `["jj", *args]` - Appends `["--ignore-working-copy"]` if `snapshot=False` - Appends `["--color", color]` if `color is not None` - Sets stderr handling based on `suppress_stderr` and `capture_stderr` flags - Captures stdout via `subprocess.PIPE` and decodes as UTF-8 - On error, raises `JJError` with the command's stdout and exit code ### Example ```python # Basic log query output = jj(["log", "-r", "@", "-T", "change_id"]) # Query without snapshotting the working copy root = jj(["workspace", "root"], snapshot=False) # Suppress stderr to avoid showing error details try: result = jj(["some", "command"], suppress_stderr=True) except JJError as e: logger.error(f"jj failed: {e.message}") ``` ``` -------------------------------- ### Execute JJ Command Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Use this function to run any `jj` CLI command and capture its standard output. Configure stderr handling and colorization as needed. It raises `JJError` on command failure. ```python def jj( args: list[str], snapshot: bool = True, suppress_stderr: bool = False, capture_stderr: bool = False, color: Literal["always", "never", "debug", "auto"] | None = "never", ) -> str ``` ```python # Basic log query output = jj(["log", "-r", "@", "-T", "change_id"]) ``` ```python # Query without snapshotting the working copy root = jj(["workspace", "root"], snapshot=False) ``` ```python # Suppress stderr to avoid showing error details try: result = jj(["some", "command"], suppress_stderr=True) except JJError as e: logger.error(f"jj failed: {e.message}") ``` -------------------------------- ### new Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/jj.md Creates a new working copy commit. This function is equivalent to running `jj new [ref]` in the command line. It can create a new commit as a child of the current working commit or a specified revision. ```APIDOC ## new ### Description Creates a new working copy commit. Equivalent to `jj new [ref]`. ### Method `new(ref: str | None = None) -> None` ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Request Example ```python # Create a new commit on top of the current revision new() # Create a new commit as a child of a specific revision new("main") ``` ### Response #### Success Response (200) * None #### Response Example * None ### Throws * `JJError`: If the jj command fails. ``` -------------------------------- ### Set Mode via Environment Variable Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Set the JJ_PRE_PUSH_MODE environment variable to configure the file checking mode. This setting is experimental. ```bash export JJ_PRE_PUSH_MODE=remote-ancestors jj-pre-push push origin main ``` -------------------------------- ### get_remote_bookmark_updates Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/bookmark-updates.md Determines the set of bookmark updates that would occur if a `jj git push` command were executed with the specified arguments. It simulates the push using `--dry-run` and then parses the output. ```APIDOC ## get_remote_bookmark_updates ### Description Determines which bookmarks will be updated by a `jj git push` command with the given arguments. This function simulates the push operation using `--dry-run` and parses the output to provide a predictable outcome. ### Method Signature ```python def get_remote_bookmark_updates(jj_git_push_args: list[str]) -> set[BookmarkUpdate] ``` ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None ### Parameters - **jj_git_push_args** (`list[str]`) - Required - Command-line arguments to pass to `jj git push` (e.g., `["origin", "main", "-r", "commit_id"]`). ### Return Type `set[BookmarkUpdate]` - A set of `BookmarkUpdate` objects representing all updates that would be pushed. ### Throws - **JJError**: If the `jj git push --dry-run` command fails during execution. - **ValueError**: If parsing the output of the dry-run command fails (delegated to `parse_git_push_dry_run`). ### Behavior 1. Constructs the command `jj git push --dry-run {jj_git_push_args}`. 2. Executes the command using `jj(args, snapshot=False, capture_stderr=True)`. 3. Logs the command output at the DEBUG level for troubleshooting purposes. 4. Parses the command's output using `parse_git_push_dry_run()` and returns the resulting set of bookmark updates. ### Example ```python # Determine what will be pushed when running: jj git push origin main updates = get_remote_bookmark_updates(["origin", "main"]) print(f"Will update {len(updates)} bookmarks") for update in updates: print(f" {update}") # With revision specification: jj git push -r commit_id updates_with_rev = get_remote_bookmark_updates(["-r", "a1b2c3d4"]) ``` ``` -------------------------------- ### Parse jj git push --dry-run Output Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/bookmark-updates.md Parses the stdout of `jj git push --dry-run` to extract bookmark update details. Supports both current and legacy output formats. ```python def parse_git_push_dry_run(output: str) -> set[BookmarkUpdate]: """ Parses the stdout of `jj git push --dry-run` and extracts bookmark update details. """ # ... implementation details ... pass ``` ```python output = """ Changes to push to origin: bookmark: main [move forward from d964e724c76e to a81d749233ff] bookmark: feature [add to 591f7e9aae85] Dry-run requested, not pushing. """ updates = parse_git_push_dry_run(output) # Returns: # { # BookmarkUpdate("origin", "main", "move_forward", "d964e724c76e", "a81d749233ff"), # BookmarkUpdate("origin", "feature", "add", None, "591f7e9aae85") # } ``` -------------------------------- ### Set Log Level via Command-Line Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md Use the --log-level option to set the logging level for diagnostic output. Accepts standard Python logging level names. ```bash jj-pre-push --log-level=DEBUG push origin main ``` -------------------------------- ### Settings Data Class Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/types.md Represents CLI settings, including the checker executable and mode. Passed through Typer context. ```python from dataclasses import dataclass from jj_pre_push.cli import Mode @dataclass class Settings: checker: str mode: Mode ``` -------------------------------- ### Working Copy State During Checks Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/architecture.md Describes the state of the working copy before, during, and after the checks are performed by jj-pre-push. ```text Before checks: - User's working copy is at some commit (orig_wc) - A temporary bookmark is created on orig_wc to prevent it from being garbage collected During checks: - For each bookmark to push: - If it's safe to reuse the original working commit (it's empty and is the direct parent), edit to that commit - Otherwise, create a new commit (`jj new`) as a child of the bookmark - Run checks in that commit - Note any modifications made by checks After checks: - Return to orig_wc (by change ID, not the temp bookmark) - Forget the temporary bookmark - If checks modified files, those modifications are preserved in the working commit ``` -------------------------------- ### Bookmark Update Regex Patterns Dictionary Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/bookmark-updates.md This dictionary maps bookmark update types to lists of regex patterns for current and legacy jj output formats. Each pattern includes named groups for bookmark name and commit IDs. ```python _bookmark_update_patterns: dict[BookmarkUpdateType, list[re.Pattern]] = { ... } ``` -------------------------------- ### Determine Remote Bookmark Updates Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/api-reference/bookmark-updates.md Determines which bookmarks will be updated by a `jj git push` command. It constructs and executes `jj git push --dry-run` with the provided arguments. ```python def get_remote_bookmark_updates(jj_git_push_args: list[str]) -> set[BookmarkUpdate]: """ Determines which bookmarks will be updated by a `jj git push` command with the given arguments. """ # ... implementation details ... pass ``` ```python # Determine what will be pushed when running: jj git push origin main updates = get_remote_bookmark_updates(["origin", "main"]) print(f"Will update {len(updates)} bookmarks") for update in updates: print(f" {update}") # With revision specification: jj git push -r commit_id updates = get_remote_bookmark_updates(["-r", "a1b2c3d4"]) ``` -------------------------------- ### Execute Custom jj Alias Source: https://github.com/acarapetis/jj-pre-push/blob/main/_autodocs/configuration.md After defining the custom 'push' alias in .jj/config.toml, you can execute it directly. This command will trigger the jj-pre-push logic configured within the alias. ```bash jj push origin main ``` -------------------------------- ### jjui key bindings for custom actions Source: https://github.com/acarapetis/jj-pre-push/blob/main/README.md Bind keyboard sequences in jjui to the custom 'jj-push' and 'jj-push-selected' actions. These actions invoke jj-pre-push. ```lua [[bindings]] action = "jj-push" seq = ["x", "p"] scope = "revisions" desc = "jj push" [[bindings]] action = "jj-push-selected" seq = ["x", "P"] scope = "revisions" desc = "jj push selected bookmark(s)" ```