gitgrip 2.0.0a1__tar.gz → 2.0.0a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitgrip-2.0.0a2/PKG-INFO +116 -0
- gitgrip-2.0.0a2/README.md +101 -0
- gitgrip-2.0.0a2/gitgrip.egg-info/PKG-INFO +116 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gitgrip.egg-info/SOURCES.txt +6 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/lane_workspace_prototype.py +30 -1
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/pyproject.toml +3 -2
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/app.py +204 -10
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/commit.py +88 -2
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/execops.py +12 -1
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/git_review.py +48 -11
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/gitops.py +121 -12
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/review_run.py +45 -11
- gitgrip-2.0.0a2/python_cli/review_runners.py +292 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/spec_apply.py +6 -1
- gitgrip-2.0.0a2/tests/test_exec_apostrophe_and_oserror.py +279 -0
- gitgrip-2.0.0a2/tests/test_exec_single_string_and_materialize_plan.py +442 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_git_review.py +93 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_lane_lifecycle_safety.py +5 -0
- gitgrip-2.0.0a2/tests/test_lane_repo_paths_and_all_skipped.py +234 -0
- gitgrip-2.0.0a2/tests/test_readme_verbs_exist.py +151 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_cli.py +41 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_runners.py +168 -1
- gitgrip-2.0.0a2/tests/test_single_repo_cwd_refusal.py +158 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_version_static.py +2 -2
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_workspace_init_from_topology.py +2 -1
- gitgrip-2.0.0a2/tests/test_workspace_init_local_repos.py +120 -0
- gitgrip-2.0.0a1/PKG-INFO +0 -13
- gitgrip-2.0.0a1/README.md +0 -258
- gitgrip-2.0.0a1/gitgrip.egg-info/PKG-INFO +0 -13
- gitgrip-2.0.0a1/python_cli/review_runners.py +0 -133
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gitgrip.egg-info/dependency_links.txt +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gitgrip.egg-info/entry_points.txt +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gitgrip.egg-info/requires.txt +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gitgrip.egg-info/top_level.txt +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/__init__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/__init__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/activate.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/agent_manifest.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/cross_repo.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/drivers.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/introspection.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/language_drivers.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/objects.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/perf.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/refs.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/trust.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/types.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/units.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/overlay/workspace_spec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2/schemas/gr2-materialization-plan-v1.schema.json +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/gr2_overlay/__init__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/__init__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/cache_materialization_probe.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/concurrent_event_stress.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/concurrent_lease_stress.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/concurrent_workspace_cap_stress.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/contribution_protocol.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/cross_mode_lane_stress.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/jsonl_store.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/layout_model_probe.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/propagation_daemon.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/propagation_state_machine.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/python_exec_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/python_hook_runtime_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/python_migration_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/python_review_checkout_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/python_spec_apply_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/real_git_lane_materialization.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/real_git_playground.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/recall_lane_history.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/repo_maintenance_prototype.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/prototypes/repo_transport_probe.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/__init__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/__main__.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/add.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/branch.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/channel_bridge.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/clone_exec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/config.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/env_exec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/events.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/failures.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/file_exec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/grip.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/grip_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/hooks.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/launch_exec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/merge_verification.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/migration.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/open_gr_review.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/platform.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/pr.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/project_review.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/prune.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/push.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/review.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/review_dispatch.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/review_ephemeral.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/review_rebind.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/staging_cleanup.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/syncops.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/target.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/python_cli/workspace_snapshot.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/setup.cfg +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_add.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_agent_manifest_overlay_source.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_app_event_outcomes.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_apply_convergence.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_branch.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_channel_bridge.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_clone_materialization.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_commit.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_config_base_path_guard.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_config_overlay.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_conftest_git_isolation.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_contribution_protocol.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_ensure_lane_checkout_reference_clone.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_env_materialization.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_event_log_integrity.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_event_outcome_policy.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_events.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_events_torn_line.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_execops.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_failure_event_outcome.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_foreground_launch_runtime.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_gr2_packaging.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_gr2_review_receipt.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_grip_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_grip_hardening.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_grip_object_model.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_grip_snapshot.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_hook_events.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_hook_hardening.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_jsonl_store.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_lane_create_fork_base_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_lane_lease_show_json.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_lane_toml_serialization.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_launch_primitive.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_m2_overlay_hindsight.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_m2_overlay_mem0.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_m2_overlay_zep.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_materialization_plan_contract.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_merge_evidence.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_merge_parent_verification.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_migration.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_migration_overlay_compatibility.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_no_bare_python_cli_imports.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_null_current_lane_refusal.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_open_gr_enter.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_open_project_refusal_reason_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_acceptance.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_activate.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_cli_wiring.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_composition_merge.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_cross_repo_atomic_apply.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_cross_repo_perf_gate.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_cross_repo_rollback.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_driver_registry.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_introspection.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_multi_stack.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_object_encoding.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_perf_gates.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_python_driver.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_tier_b_encoding.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_tier_b_perf_gates.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_tier_b_repo_state.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_tier_b_staging_discipline.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_trust_model.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_overlay_workspace_spec.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_pr_events.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_pr_merge_method.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_pr_merge_partial_failure.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_project_file_materialization.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_project_review_range_reconstruction.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_project_review_three_repo.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_projection_tracked_dest.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_propagation_contribution.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_propagation_daemon.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_propagation_state_machine.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_prune.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_push.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_repo_status_linked_worktree.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_repo_status_schema_version.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_repo_status_symlinked_git_dir.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_bind_fork_base.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_bind_from_range.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_bind_verify.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_close_gr.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_create_project_cli.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_dispatch.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_ephemeral.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_open_lane.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_rebind.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_run.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_run_import_isolation.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_run_rerun_and_refusal_receipt.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_review_verify_inside.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_rmtree_or_refuse.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_snapshot_id_prefix_resolution.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_spec_apply_event_outcomes.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sprint21_sync_platform.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_staging_cleanup.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_store_verb_rename.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_event_outcomes.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_fast_forward.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_fetch.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_seed_local.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_ssh_rewrite.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_sync_status_probe.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_target.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_tmux_launch_runtime.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_abort.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_apply.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_apply_dry_run.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_manifest_schema.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_propose.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_unit_topological_apply.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_workspace_convert_clone.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_workspace_edit_lease_cap.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_workspace_identity_boundary.py +0 -0
- {gitgrip-2.0.0a1 → gitgrip-2.0.0a2}/tests/test_workspace_snapshot.py +0 -0
gitgrip-2.0.0a2/PKG-INFO
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitgrip
|
|
3
|
+
Version: 2.0.0a2
|
|
4
|
+
Summary: Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: typer>=0.9
|
|
8
|
+
Requires-Dist: tomli_w>=1.0
|
|
9
|
+
Requires-Dist: pyyaml>=6.0
|
|
10
|
+
Requires-Dist: toml>=0.10
|
|
11
|
+
Requires-Dist: jsonschema>=4.18
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
14
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
15
|
+
|
|
16
|
+
# gr2
|
|
17
|
+
|
|
18
|
+
**gr2 is the workspace layer for multi-repo work.** One repository is just git; when a change spans repositories — a feature slice, a release, several agents touching several repos — gr2 gives you a workspace over them, isolated lanes to work in, and one grouped review/PR set for the slice. It is the Python successor to the Rust `gr` (1.x, called gr1 below); both ship from this repository, and `gr2` is the command for the workspace and the slice.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 -m venv ~/gr2-venv && source ~/gr2-venv/bin/activate
|
|
24
|
+
pip install --pre gitgrip # the PyPI package is "gitgrip"; the command is "gr2"
|
|
25
|
+
gr2 --version
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`--pre` is required while 2.x is an alpha — without it pip installs 1.5.1, which is gr1. To run unreleased development code instead, install from a checkout: `pip install -e gr2/` from the repository root.
|
|
29
|
+
|
|
30
|
+
The Rust `gr` (gr1, 1.x) installs with `brew install synapt-dev/tap/gitgrip` or `cargo install gitgrip`. The two do not collide; you can have both installed.
|
|
31
|
+
|
|
32
|
+
## First five minutes
|
|
33
|
+
|
|
34
|
+
Every command below was run, in this order, in a clean virtualenv against a throwaway workspace of two repositories. Put two clones side by side in one folder, say `~/ws/repo-a` and `~/ws/repo-b`.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd ~/ws
|
|
38
|
+
gr2 workspace init ~/ws # scans the folder; writes .grip/workspace_spec.toml
|
|
39
|
+
gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
|
|
40
|
+
gr2 workspace status ~/ws # what kind of workspace this is
|
|
41
|
+
gr2 store init ~/ws # the workspace snapshot store (needed before review)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A **unit** is one worker — you, or one agent — and `default` is created for you. A **lane** is one piece of work spanning repos, with its own clones, so two lanes never step on each other:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
|
|
48
|
+
gr2 lane enter ~/ws default feat-x --actor human:you
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Both commands print, per repo, the absolute directory you work in:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
55
|
+
repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Edit there — not in your original clones. Stage and commit across the lane's repos:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
62
|
+
gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`commit` with the lane flags commits every lane repo that has staged changes and names the repos it skipped. If every repo was skipped it exits non-zero with one sentence naming where it looked — and, when it can see them, where your staged changes actually are. Run one command across every lane repo, then turn the lane into one reviewable object:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
|
|
69
|
+
gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
|
|
70
|
+
gr2 lane current ~/ws default # where am I?
|
|
71
|
+
gr2 lane exit ~/ws default --actor human:you
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
|
|
75
|
+
|
|
76
|
+
## What works today, and what is not there yet
|
|
77
|
+
|
|
78
|
+
Alpha 2 is a working local workspace layer. Verified by running the walk above:
|
|
79
|
+
|
|
80
|
+
- `workspace` (init, materialize, status, migrate-gr1 from a gr1 gripspace), `lane` (create, enter, exit, current, lease), `store` (init, snapshot, log, diff, checkout), `exec run`, `repo status`, `sync status`, `review create-project`.
|
|
81
|
+
- Lanes are independent clones: two lanes, or two agents, never share refs, an index, or a working tree.
|
|
82
|
+
- A lane commit that commits nothing anywhere refuses loudly instead of reporting success.
|
|
83
|
+
|
|
84
|
+
Not there yet:
|
|
85
|
+
|
|
86
|
+
- The full walk with **remote** PRs (`gr2 push`, `gr2 pr create`) is documented in `--help` but was not exercised in a clean environment for this README; treat those two as alpha.
|
|
87
|
+
- `gr2 --help` and some verb output still say "prototype" in places; the wording is being cleaned up as verbs land.
|
|
88
|
+
- The Rust `gr` (gr1) still owns `spawn`, `fleet`, and `manifest` until their gr2 ports land. Everything else — workspace sync, lanes, the multi-repo slice, its review — is gr2's job; if a verb is missing or wrong there, that is a bug worth reporting, not a reason to reach for gr1.
|
|
89
|
+
|
|
90
|
+
## Commands
|
|
91
|
+
|
|
92
|
+
| Group | Verbs |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, migrate-lane-state, bootstrap-gr1 |
|
|
95
|
+
| `spec` | show, validate |
|
|
96
|
+
| `lane` | create, enter, exit, current, resolve, bind, lease |
|
|
97
|
+
| (top level) | branch, add, commit, push, prune |
|
|
98
|
+
| `sync` | status, run |
|
|
99
|
+
| `pr` | create, status, checks, merge |
|
|
100
|
+
| `review` | open, close, checkout-pr, run, requirements, bind, verify, rebind, create-project |
|
|
101
|
+
| `exec` | status, run |
|
|
102
|
+
| `repo` | status, hooks, hook-run, projection-run |
|
|
103
|
+
| `store` | init, snapshot, log, diff, checkout |
|
|
104
|
+
| `target`, `config`, `plan`, `apply` | stored PR target; config overlays; show/apply the materialization plan |
|
|
105
|
+
|
|
106
|
+
## Overlay substrate
|
|
107
|
+
|
|
108
|
+
gr2 also carries the config-overlay substrate (capture, compose, and materialize configuration layers over a workspace): see [docs/OVERLAY-SUBSTRATE.md](docs/OVERLAY-SUBSTRATE.md).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install -e "gr2[dev]" # from the repository root
|
|
114
|
+
cd gr2 && pytest # the gr2 suite (tests + overlay tests)
|
|
115
|
+
cd gr2 && ruff check . # lint, same config as CI
|
|
116
|
+
```
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# gr2
|
|
2
|
+
|
|
3
|
+
**gr2 is the workspace layer for multi-repo work.** One repository is just git; when a change spans repositories — a feature slice, a release, several agents touching several repos — gr2 gives you a workspace over them, isolated lanes to work in, and one grouped review/PR set for the slice. It is the Python successor to the Rust `gr` (1.x, called gr1 below); both ship from this repository, and `gr2` is the command for the workspace and the slice.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python3 -m venv ~/gr2-venv && source ~/gr2-venv/bin/activate
|
|
9
|
+
pip install --pre gitgrip # the PyPI package is "gitgrip"; the command is "gr2"
|
|
10
|
+
gr2 --version
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`--pre` is required while 2.x is an alpha — without it pip installs 1.5.1, which is gr1. To run unreleased development code instead, install from a checkout: `pip install -e gr2/` from the repository root.
|
|
14
|
+
|
|
15
|
+
The Rust `gr` (gr1, 1.x) installs with `brew install synapt-dev/tap/gitgrip` or `cargo install gitgrip`. The two do not collide; you can have both installed.
|
|
16
|
+
|
|
17
|
+
## First five minutes
|
|
18
|
+
|
|
19
|
+
Every command below was run, in this order, in a clean virtualenv against a throwaway workspace of two repositories. Put two clones side by side in one folder, say `~/ws/repo-a` and `~/ws/repo-b`.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cd ~/ws
|
|
23
|
+
gr2 workspace init ~/ws # scans the folder; writes .grip/workspace_spec.toml
|
|
24
|
+
gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
|
|
25
|
+
gr2 workspace status ~/ws # what kind of workspace this is
|
|
26
|
+
gr2 store init ~/ws # the workspace snapshot store (needed before review)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A **unit** is one worker — you, or one agent — and `default` is created for you. A **lane** is one piece of work spanning repos, with its own clones, so two lanes never step on each other:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
|
|
33
|
+
gr2 lane enter ~/ws default feat-x --actor human:you
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Both commands print, per repo, the absolute directory you work in:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
40
|
+
repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Edit there — not in your original clones. Stage and commit across the lane's repos:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
47
|
+
gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`commit` with the lane flags commits every lane repo that has staged changes and names the repos it skipped. If every repo was skipped it exits non-zero with one sentence naming where it looked — and, when it can see them, where your staged changes actually are. Run one command across every lane repo, then turn the lane into one reviewable object:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
|
|
54
|
+
gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
|
|
55
|
+
gr2 lane current ~/ws default # where am I?
|
|
56
|
+
gr2 lane exit ~/ws default --actor human:you
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
|
|
60
|
+
|
|
61
|
+
## What works today, and what is not there yet
|
|
62
|
+
|
|
63
|
+
Alpha 2 is a working local workspace layer. Verified by running the walk above:
|
|
64
|
+
|
|
65
|
+
- `workspace` (init, materialize, status, migrate-gr1 from a gr1 gripspace), `lane` (create, enter, exit, current, lease), `store` (init, snapshot, log, diff, checkout), `exec run`, `repo status`, `sync status`, `review create-project`.
|
|
66
|
+
- Lanes are independent clones: two lanes, or two agents, never share refs, an index, or a working tree.
|
|
67
|
+
- A lane commit that commits nothing anywhere refuses loudly instead of reporting success.
|
|
68
|
+
|
|
69
|
+
Not there yet:
|
|
70
|
+
|
|
71
|
+
- The full walk with **remote** PRs (`gr2 push`, `gr2 pr create`) is documented in `--help` but was not exercised in a clean environment for this README; treat those two as alpha.
|
|
72
|
+
- `gr2 --help` and some verb output still say "prototype" in places; the wording is being cleaned up as verbs land.
|
|
73
|
+
- The Rust `gr` (gr1) still owns `spawn`, `fleet`, and `manifest` until their gr2 ports land. Everything else — workspace sync, lanes, the multi-repo slice, its review — is gr2's job; if a verb is missing or wrong there, that is a bug worth reporting, not a reason to reach for gr1.
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
| Group | Verbs |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, migrate-lane-state, bootstrap-gr1 |
|
|
80
|
+
| `spec` | show, validate |
|
|
81
|
+
| `lane` | create, enter, exit, current, resolve, bind, lease |
|
|
82
|
+
| (top level) | branch, add, commit, push, prune |
|
|
83
|
+
| `sync` | status, run |
|
|
84
|
+
| `pr` | create, status, checks, merge |
|
|
85
|
+
| `review` | open, close, checkout-pr, run, requirements, bind, verify, rebind, create-project |
|
|
86
|
+
| `exec` | status, run |
|
|
87
|
+
| `repo` | status, hooks, hook-run, projection-run |
|
|
88
|
+
| `store` | init, snapshot, log, diff, checkout |
|
|
89
|
+
| `target`, `config`, `plan`, `apply` | stored PR target; config overlays; show/apply the materialization plan |
|
|
90
|
+
|
|
91
|
+
## Overlay substrate
|
|
92
|
+
|
|
93
|
+
gr2 also carries the config-overlay substrate (capture, compose, and materialize configuration layers over a workspace): see [docs/OVERLAY-SUBSTRATE.md](docs/OVERLAY-SUBSTRATE.md).
|
|
94
|
+
|
|
95
|
+
## Development
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install -e "gr2[dev]" # from the repository root
|
|
99
|
+
cd gr2 && pytest # the gr2 suite (tests + overlay tests)
|
|
100
|
+
cd gr2 && ruff check . # lint, same config as CI
|
|
101
|
+
```
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitgrip
|
|
3
|
+
Version: 2.0.0a2
|
|
4
|
+
Summary: Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: typer>=0.9
|
|
8
|
+
Requires-Dist: tomli_w>=1.0
|
|
9
|
+
Requires-Dist: pyyaml>=6.0
|
|
10
|
+
Requires-Dist: toml>=0.10
|
|
11
|
+
Requires-Dist: jsonschema>=4.18
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
14
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
15
|
+
|
|
16
|
+
# gr2
|
|
17
|
+
|
|
18
|
+
**gr2 is the workspace layer for multi-repo work.** One repository is just git; when a change spans repositories — a feature slice, a release, several agents touching several repos — gr2 gives you a workspace over them, isolated lanes to work in, and one grouped review/PR set for the slice. It is the Python successor to the Rust `gr` (1.x, called gr1 below); both ship from this repository, and `gr2` is the command for the workspace and the slice.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 -m venv ~/gr2-venv && source ~/gr2-venv/bin/activate
|
|
24
|
+
pip install --pre gitgrip # the PyPI package is "gitgrip"; the command is "gr2"
|
|
25
|
+
gr2 --version
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`--pre` is required while 2.x is an alpha — without it pip installs 1.5.1, which is gr1. To run unreleased development code instead, install from a checkout: `pip install -e gr2/` from the repository root.
|
|
29
|
+
|
|
30
|
+
The Rust `gr` (gr1, 1.x) installs with `brew install synapt-dev/tap/gitgrip` or `cargo install gitgrip`. The two do not collide; you can have both installed.
|
|
31
|
+
|
|
32
|
+
## First five minutes
|
|
33
|
+
|
|
34
|
+
Every command below was run, in this order, in a clean virtualenv against a throwaway workspace of two repositories. Put two clones side by side in one folder, say `~/ws/repo-a` and `~/ws/repo-b`.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd ~/ws
|
|
38
|
+
gr2 workspace init ~/ws # scans the folder; writes .grip/workspace_spec.toml
|
|
39
|
+
gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
|
|
40
|
+
gr2 workspace status ~/ws # what kind of workspace this is
|
|
41
|
+
gr2 store init ~/ws # the workspace snapshot store (needed before review)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A **unit** is one worker — you, or one agent — and `default` is created for you. A **lane** is one piece of work spanning repos, with its own clones, so two lanes never step on each other:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
|
|
48
|
+
gr2 lane enter ~/ws default feat-x --actor human:you
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Both commands print, per repo, the absolute directory you work in:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
55
|
+
repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Edit there — not in your original clones. Stage and commit across the lane's repos:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
|
|
62
|
+
gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`commit` with the lane flags commits every lane repo that has staged changes and names the repos it skipped. If every repo was skipped it exits non-zero with one sentence naming where it looked — and, when it can see them, where your staged changes actually are. Run one command across every lane repo, then turn the lane into one reviewable object:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
|
|
69
|
+
gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
|
|
70
|
+
gr2 lane current ~/ws default # where am I?
|
|
71
|
+
gr2 lane exit ~/ws default --actor human:you
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
|
|
75
|
+
|
|
76
|
+
## What works today, and what is not there yet
|
|
77
|
+
|
|
78
|
+
Alpha 2 is a working local workspace layer. Verified by running the walk above:
|
|
79
|
+
|
|
80
|
+
- `workspace` (init, materialize, status, migrate-gr1 from a gr1 gripspace), `lane` (create, enter, exit, current, lease), `store` (init, snapshot, log, diff, checkout), `exec run`, `repo status`, `sync status`, `review create-project`.
|
|
81
|
+
- Lanes are independent clones: two lanes, or two agents, never share refs, an index, or a working tree.
|
|
82
|
+
- A lane commit that commits nothing anywhere refuses loudly instead of reporting success.
|
|
83
|
+
|
|
84
|
+
Not there yet:
|
|
85
|
+
|
|
86
|
+
- The full walk with **remote** PRs (`gr2 push`, `gr2 pr create`) is documented in `--help` but was not exercised in a clean environment for this README; treat those two as alpha.
|
|
87
|
+
- `gr2 --help` and some verb output still say "prototype" in places; the wording is being cleaned up as verbs land.
|
|
88
|
+
- The Rust `gr` (gr1) still owns `spawn`, `fleet`, and `manifest` until their gr2 ports land. Everything else — workspace sync, lanes, the multi-repo slice, its review — is gr2's job; if a verb is missing or wrong there, that is a bug worth reporting, not a reason to reach for gr1.
|
|
89
|
+
|
|
90
|
+
## Commands
|
|
91
|
+
|
|
92
|
+
| Group | Verbs |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, migrate-lane-state, bootstrap-gr1 |
|
|
95
|
+
| `spec` | show, validate |
|
|
96
|
+
| `lane` | create, enter, exit, current, resolve, bind, lease |
|
|
97
|
+
| (top level) | branch, add, commit, push, prune |
|
|
98
|
+
| `sync` | status, run |
|
|
99
|
+
| `pr` | create, status, checks, merge |
|
|
100
|
+
| `review` | open, close, checkout-pr, run, requirements, bind, verify, rebind, create-project |
|
|
101
|
+
| `exec` | status, run |
|
|
102
|
+
| `repo` | status, hooks, hook-run, projection-run |
|
|
103
|
+
| `store` | init, snapshot, log, diff, checkout |
|
|
104
|
+
| `target`, `config`, `plan`, `apply` | stored PR target; config overlays; show/apply the materialization plan |
|
|
105
|
+
|
|
106
|
+
## Overlay substrate
|
|
107
|
+
|
|
108
|
+
gr2 also carries the config-overlay substrate (capture, compose, and materialize configuration layers over a workspace): see [docs/OVERLAY-SUBSTRATE.md](docs/OVERLAY-SUBSTRATE.md).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install -e "gr2[dev]" # from the repository root
|
|
114
|
+
cd gr2 && pytest # the gr2 suite (tests + overlay tests)
|
|
115
|
+
cd gr2 && ruff check . # lint, same config as CI
|
|
116
|
+
```
|
|
@@ -103,6 +103,8 @@ tests/test_event_log_integrity.py
|
|
|
103
103
|
tests/test_event_outcome_policy.py
|
|
104
104
|
tests/test_events.py
|
|
105
105
|
tests/test_events_torn_line.py
|
|
106
|
+
tests/test_exec_apostrophe_and_oserror.py
|
|
107
|
+
tests/test_exec_single_string_and_materialize_plan.py
|
|
106
108
|
tests/test_execops.py
|
|
107
109
|
tests/test_failure_event_outcome.py
|
|
108
110
|
tests/test_foreground_launch_runtime.py
|
|
@@ -119,6 +121,7 @@ tests/test_jsonl_store.py
|
|
|
119
121
|
tests/test_lane_create_fork_base_cli.py
|
|
120
122
|
tests/test_lane_lease_show_json.py
|
|
121
123
|
tests/test_lane_lifecycle_safety.py
|
|
124
|
+
tests/test_lane_repo_paths_and_all_skipped.py
|
|
122
125
|
tests/test_lane_toml_serialization.py
|
|
123
126
|
tests/test_launch_primitive.py
|
|
124
127
|
tests/test_m2_overlay_hindsight.py
|
|
@@ -165,6 +168,7 @@ tests/test_propagation_daemon.py
|
|
|
165
168
|
tests/test_propagation_state_machine.py
|
|
166
169
|
tests/test_prune.py
|
|
167
170
|
tests/test_push.py
|
|
171
|
+
tests/test_readme_verbs_exist.py
|
|
168
172
|
tests/test_repo_status_linked_worktree.py
|
|
169
173
|
tests/test_repo_status_schema_version.py
|
|
170
174
|
tests/test_repo_status_symlinked_git_dir.py
|
|
@@ -184,6 +188,7 @@ tests/test_review_run_rerun_and_refusal_receipt.py
|
|
|
184
188
|
tests/test_review_runners.py
|
|
185
189
|
tests/test_review_verify_inside.py
|
|
186
190
|
tests/test_rmtree_or_refuse.py
|
|
191
|
+
tests/test_single_repo_cwd_refusal.py
|
|
187
192
|
tests/test_snapshot_id_prefix_resolution.py
|
|
188
193
|
tests/test_spec_apply_event_outcomes.py
|
|
189
194
|
tests/test_sprint21_sync_platform.py
|
|
@@ -208,4 +213,5 @@ tests/test_workspace_convert_clone.py
|
|
|
208
213
|
tests/test_workspace_edit_lease_cap.py
|
|
209
214
|
tests/test_workspace_identity_boundary.py
|
|
210
215
|
tests/test_workspace_init_from_topology.py
|
|
216
|
+
tests/test_workspace_init_local_repos.py
|
|
211
217
|
tests/test_workspace_snapshot.py
|
|
@@ -195,6 +195,7 @@ class LaneTransitionOutcome:
|
|
|
195
195
|
current_lane: str | None
|
|
196
196
|
state_path: Path
|
|
197
197
|
status: str = "ok"
|
|
198
|
+
repo_paths: dict[str, str] = dataclasses.field(default_factory=dict)
|
|
198
199
|
|
|
199
200
|
@property
|
|
200
201
|
def exit_code(self) -> int:
|
|
@@ -208,6 +209,7 @@ class LaneTransitionOutcome:
|
|
|
208
209
|
"previous_lane": self.previous_lane,
|
|
209
210
|
"current_lane": self.current_lane,
|
|
210
211
|
"state_path": str(self.state_path),
|
|
212
|
+
"repo_paths": dict(self.repo_paths),
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
|
|
@@ -1038,6 +1040,18 @@ def create_lane(args: argparse.Namespace) -> int:
|
|
|
1038
1040
|
(lane_root / "context").mkdir()
|
|
1039
1041
|
atomic_replace_text(metadata_path, expected)
|
|
1040
1042
|
print(metadata_path)
|
|
1043
|
+
# The human line names where the actor works, per repo, absolute: a
|
|
1044
|
+
# materialized lane's repos live under its lane tree, a bound lane's one
|
|
1045
|
+
# repo IS the bound worktree. (The stranger's F2 finding: enter/create
|
|
1046
|
+
# used to point at lane.toml only, so the actor never learned where the
|
|
1047
|
+
# lane's repos are.)
|
|
1048
|
+
if lane_kind == "bound" and bound_worktree:
|
|
1049
|
+
for repo in repos:
|
|
1050
|
+
print(f"{repo}: {bound_worktree}")
|
|
1051
|
+
else:
|
|
1052
|
+
lane_root = lane_dir(workspace_root, args.owner_unit, args.lane_name)
|
|
1053
|
+
for repo in repos:
|
|
1054
|
+
print(f"{repo}: {lane_root / 'repos' / repo}")
|
|
1041
1055
|
return 0
|
|
1042
1056
|
|
|
1043
1057
|
|
|
@@ -1222,6 +1236,17 @@ def enter_lane(args: argparse.Namespace) -> LaneTransitionOutcome:
|
|
|
1222
1236
|
previous_lane = current.get("lane_name")
|
|
1223
1237
|
previous.insert(0, current)
|
|
1224
1238
|
|
|
1239
|
+
lane_kind = lane_doc.get("lane_kind", "materialized")
|
|
1240
|
+
if lane_kind == "bound" and lane_doc.get("bound_worktree"):
|
|
1241
|
+
repo_paths = {
|
|
1242
|
+
r: str(lane_doc["bound_worktree"]) for r in lane_doc.get("repos", [])
|
|
1243
|
+
}
|
|
1244
|
+
else:
|
|
1245
|
+
lane_root = lane_dir(workspace_root, args.owner_unit, args.lane_name)
|
|
1246
|
+
repo_paths = {
|
|
1247
|
+
r: str(lane_root / "repos" / r) for r in lane_doc.get("repos", [])
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1225
1250
|
deduped: list[dict] = []
|
|
1226
1251
|
seen: set[tuple[str, str]] = set()
|
|
1227
1252
|
for item in previous:
|
|
@@ -1237,6 +1262,7 @@ def enter_lane(args: argparse.Namespace) -> LaneTransitionOutcome:
|
|
|
1237
1262
|
"lane_name": args.lane_name,
|
|
1238
1263
|
"lane_type": lane_doc["lane_type"],
|
|
1239
1264
|
"repos": lane_doc.get("repos", []),
|
|
1265
|
+
"repo_paths": repo_paths,
|
|
1240
1266
|
"actor": args.actor,
|
|
1241
1267
|
"entered_at": now_utc(),
|
|
1242
1268
|
},
|
|
@@ -1270,7 +1296,10 @@ def enter_lane(args: argparse.Namespace) -> LaneTransitionOutcome:
|
|
|
1270
1296
|
"timestamp": event["timestamp"],
|
|
1271
1297
|
},
|
|
1272
1298
|
)
|
|
1273
|
-
return LaneTransitionOutcome(
|
|
1299
|
+
return LaneTransitionOutcome(
|
|
1300
|
+
"enter", args.owner_unit, previous_lane, args.lane_name, path,
|
|
1301
|
+
repo_paths=repo_paths,
|
|
1302
|
+
)
|
|
1274
1303
|
|
|
1275
1304
|
|
|
1276
1305
|
def exit_lane(args: argparse.Namespace) -> LaneTransitionOutcome:
|
|
@@ -11,8 +11,9 @@ name = "gitgrip"
|
|
|
11
11
|
# number and it is not derived from Cargo.toml. gr1 releases as crates.io/GitHub
|
|
12
12
|
# `v1.x.y`; gr2 releases as PyPI `gr2/v2.x.y`. Runtime reads it via
|
|
13
13
|
# importlib.metadata.version("gitgrip"), never a checked-in file.
|
|
14
|
-
version = "2.0.
|
|
15
|
-
description = "
|
|
14
|
+
version = "2.0.0a2"
|
|
15
|
+
description = "Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice"
|
|
16
|
+
readme = "README.md"
|
|
16
17
|
requires-python = ">=3.11"
|
|
17
18
|
dependencies = [
|
|
18
19
|
"typer>=0.9",
|