gitgrip 2.0.0a11__tar.gz → 2.0.0a12__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.0a11 → gitgrip-2.0.0a12}/PKG-INFO +1 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/PKG-INFO +1 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/SOURCES.txt +5 -0
- gitgrip-2.0.0a12/gr2/python_cli/_build.json +1 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/app.py +9 -9
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/approvals.py +6 -4
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/clone_exec.py +2 -2
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/gitops.py +3 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/grip_cli.py +4 -4
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/hooks.py +2 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/merge_gate.py +8 -3
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/migration.py +97 -11
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/workspace_guidance.py +2 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/pyproject.toml +1 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_branch_in_lane.py +51 -0
- gitgrip-2.0.0a12/tests/test_migrate_gr1_member_origin.py +215 -0
- gitgrip-2.0.0a12/tests/test_pin_rewind_shallow_path_quoted.py +37 -0
- gitgrip-2.0.0a12/tests/test_printed_command_values_quoted.py +140 -0
- gitgrip-2.0.0a12/tests/test_review_merge_tracking_command_quoted.py +269 -0
- gitgrip-2.0.0a12/tests/test_spec_sourced_git_lines_quoted.py +153 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_submodule_init.py +19 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_version_static.py +2 -2
- gitgrip-2.0.0a11/gr2/python_cli/_build.json +0 -1
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/README.md +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/dependency_links.txt +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/entry_points.txt +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/requires.txt +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gitgrip.egg-info/top_level.txt +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/PLATFORM_ADAPTER_CHANGELOG.md +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/__init__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/api_core.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/__init__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/activate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/agent_manifest.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/cross_repo.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/drivers.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/introspection.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/language_drivers.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/objects.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/perf.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/refs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/trust.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/types.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/units.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/overlay/workspace_spec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/__init__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/cache_materialization_probe.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/concurrent_event_stress.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/concurrent_lease_stress.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/concurrent_workspace_cap_stress.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/contribution_protocol.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/cross_mode_lane_stress.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/jsonl_store.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/lane_workspace_prototype.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/layout_model_probe.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/propagation_daemon.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/propagation_state_machine.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/python_exec_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/python_hook_runtime_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/python_migration_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/python_review_checkout_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/python_spec_apply_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/real_git_lane_materialization.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/real_git_playground.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/recall_lane_history.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/repo_maintenance_prototype.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/prototypes/repo_transport_probe.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/__init__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/__main__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/add.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/agent_record.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/approval_schema.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/arbon.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/branch_update.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/channel_bridge.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/check_records.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/commit.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/config.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/consent.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/context.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/declared_sets.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/delete.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/ecosystems_python.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/env_exec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/events.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/execops.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/exit_codes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/failures.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/file_exec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/git_review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/gitinclude.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/gr_resolver.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/gr_shadow.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/grip.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/lane_defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/lane_downstream.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/lane_graph.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/lane_plugins.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/launch_exec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/layout.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/leased_push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/member_field_tree.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/merge_receipts.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/merge_verification.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/names.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/next_steps.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/open_gr_review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/platform.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/pr.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/project_review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/proto_json.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/prune.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/read_review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_allocation.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_diff.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_dispatch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_ephemeral.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_field_tree.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_members.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_rebind.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_records.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_run.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_runners.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/review_update.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/root_option.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/set_check.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/set_hints.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/shadow.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/spec_apply.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/staging_cleanup.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/store_hooks.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/syncops.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/target.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/tracking.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/version.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/workspace_mode.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/python_cli/workspace_snapshot.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.approval.v1alpha1/approval.proto +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.approval.v1alpha1/descriptor_set.pb +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.check.v1alpha1/check.proto +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.check.v1alpha1/descriptor_set.pb +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.merge.v1alpha1/descriptor_set.pb +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.merge.v1alpha1/merge.proto +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.review.v1alpha1/descriptor_set.pb +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/dev.synapt.grip.review.v1alpha1/review.proto +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/gr2-materialization-plan-v1.schema.json +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2/schemas/gr2-workspace-spec-v1.schema.json +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/gr2_overlay/__init__.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/setup.cfg +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/setup.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_add.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_add_lane_from_a_subdirectory.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_agent_manifest_overlay_source.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_agent_record_append.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_agent_record_fold.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_agent_record_stamps.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_api_core_seam.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_api_dump.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_app_event_outcomes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_apply_convergence.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_apply_gr1_sibling_adoption.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_approval_schema.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_arbon.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_bind_merge_head_refusals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_break_17_unit_path_containment.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_break_18_gr1_sibling_units.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_channel_bridge.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_cli_adapter_error_boundary.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_cli_shape_witnesses.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_clone_materialization.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_commit.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_config_base_path_guard.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_config_overlay.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_conftest_git_isolation.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_consent_key_paths.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_context_resolver.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_contribution_protocol.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_declared_set_pins.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_declared_sets.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_defaults_from_repo.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_delete.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_deprecation_registry.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_ecosystems_python.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_ensure_lane_checkout_reference_clone.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_env_materialization.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_event_log_integrity.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_event_outcome_policy.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_events.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_events_torn_line.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_exec_apostrophe_and_oserror.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_exec_run_names_what_did_not_run.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_exec_single_string_and_materialize_plan.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_execops.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_failure_event_outcome.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_fetch_refmap.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_fetch_refmap_pr_base.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_fetch_refmap_verbs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_field_tree_name.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_field_tree_schema_reader.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_files_compose.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_first_five_minutes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_foreground_launch_runtime.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_git_positional_refusal.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_git_positional_sites.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_git_review.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_git_transport_allow_list.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gitinclude_compiler.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gitops_locating_env.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gitops_shared.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr1_first_run_guidance.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr2_packaging.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr2_review_receipt.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr_installed_wheel.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr_resolved_cleared.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr_resolver_conformance.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_gr_shadow.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_grip_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_grip_hardening.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_grip_snapshot.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_grip_toml_literals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_grip_toml_schema_v1.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hook_events.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hook_hardening.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hooks_consent.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hooks_group_names.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hostile_names.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_hostile_names_helper.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_init_advice_never_nests.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_jsonl_store.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_cache_keyed_by_member_name.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_checkout_root.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_create_defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_create_fork_base_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_create_refusal_leaves_nothing.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_create_refuses_own_branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_downstream.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_downstream_run.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_enter_hook_warnings.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_exit_keeps_dirty_work.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_graph.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_lease_show_json.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_lifecycle_safety.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_plugins.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_probe.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_probe_batch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_remove.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_repo_paths_and_all_skipped.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_roles.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_show_name.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_store_path_pins.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_lane_toml_serialization.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_launch_primitive.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_layout_census.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_leased_push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_linked_review_receipts.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_m2_overlay_hindsight.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_m2_overlay_mem0.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_m2_overlay_zep.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_malformed_remote_refusal.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_materialization_plan_contract.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_materialize_pin.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_member_working_root_checkout_materialize.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_merge_credential_remotes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_merge_evidence.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_merge_parent_verification.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_migrate_gr1_one_root.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_migration.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_migration_overlay_compatibility.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_names.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_native_store_gitinclude.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_native_store_review_record_probes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_no_bare_python_cli_imports.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_np_bench_contract_scenario.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_null_current_lane_refusal.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_one_pin_record.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_open_gr_enter.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_open_project_refusal_reason_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_out_of_set_hint.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_outbox_ack_after_effect.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_outside_names_as_git_options.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_acceptance.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_activate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_cli_wiring.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_composition_merge.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_cross_repo_atomic_apply.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_cross_repo_perf_gate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_cross_repo_rollback.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_driver_registry.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_introspection.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_multi_stack.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_object_encoding.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_perf_gates.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_python_driver.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_tier_b_encoding.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_tier_b_perf_gates.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_tier_b_repo_state.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_tier_b_staging_discipline.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_trust_model.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_overlay_workspace_spec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_platform_adapter_changelog.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_platform_adapter_plugins.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_adapter_v2_target.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_create_pins_itself.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_events.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_group_legibility.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_merge_head_pin.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_merge_method.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_merge_missing_target.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_merge_partial_failure.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_review_subject.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_pr_view.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_project_file_materialization.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_project_review_range_reconstruction.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_project_review_three_repo.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_projection_tracked_dest.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_propagation_contribution.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_propagation_daemon.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_propagation_state_machine.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_proto_json.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_prune.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_python_group_install.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_readme_verbs_exist.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_readme_walk.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_record_schema_copies.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_refusal_names_the_cause.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_remote_check_records.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_repo_maintenance_gitops.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_repo_path_read_through.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_repo_status_linked_worktree.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_repo_status_schema_version.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_repo_status_symlinked_git_dir.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_retire_gr1.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_a4.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_a4_v2.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_a4_v3.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_allocation_recovery.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_ansi_parse.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_approvals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_b3_reader_alignment.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_author.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_fork_base.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_from_range.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_migration.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_native_store.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_root_refs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_bind_verify.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_check_name.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_check_unknown.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_close_gr.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_close_keeps_local_work.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_context_defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_context_witnesses.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_create_project_cli.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_dispatch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_ephemeral.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_events.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_field_tree.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_field_tree_reader_edges.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_field_tree_readers.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_install_hint.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_json_refusals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_gate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_gate_lost_ack.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_platform.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_receipt.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_set_alone.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_set_required.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_merge_updates_tracking_ref.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_named_refusals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_open_lane.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_open_reader_lane.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pin_after_push.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pin_ratified.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pin_rows_json_help.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pin_stamp_names.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pinned_target.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_pr_marker_context.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_publish_all.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_read_pr.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_reader_defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_reads.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_rebind.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_receipt_cleanup.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_receive_no_migrate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_ref_v1_migration.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_ref_v1_reader.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_ref_v1_writer.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_remote_safety.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_context.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_deleted_cwd.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_dependency_order.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_import_isolation.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_integrity_recheck.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_multi_repo.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_package_name.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_plugin_order.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_rerun_and_refusal_receipt.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_run_venv_and_refusal_identity.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_runners.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_show_diff.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_subject.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_transport.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_update.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_v1_format_guard.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_verify_inside.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_verify_json_refusals.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_review_vocabulary.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_rmtree_or_refuse.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_root_option_verbs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_root_optional_help.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_selected_workspace_commit.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_set_check.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_set_check_credential_remote.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_set_check_merge_head.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_set_check_remote_heads.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_shadow.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_shadow_lease.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_single_repo_cwd_refusal.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_skill_dump.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_snapshot_id_prefix_resolution.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_spec_apply_event_outcomes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_spec_declaration_ref_pin.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_spec_show_native_root.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sprint21_sync_platform.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_staging_cleanup.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_break_attempts.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_check_undeclared_gitlink.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_checkout_atomicity.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_commit_compat_next_step.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_commit_follows_branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_commit_keeps_record.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_commit_noop.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_commit_refuses_rewind.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_declared_members.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_fence_no_pin.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_full_mode_carrier.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_full_mode_coverage.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_full_mode_layers.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_full_mode_records.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_git_hooks.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_git_native_smoke.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_gitmodules.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_gitmodules_branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_hook_takes_verb_coverage.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_init_branch_inference.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_init_clone.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_init_derived_spec.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_init_slot_pointer.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_init_slot_write_error.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_log_adoption_boundary.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_materialize_branch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_materialize_fetches_new_pin.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_materialize_installs_hooks.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_member_path_hygiene.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_member_state.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_migrate_branch_inference.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_moved_workspace_guard.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_push_landed_by_another.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_push_member_refs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_push_s2.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_push_s3a.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_push_s3b.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_refusal_names_both_exits.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_shadow_fence.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_shadow_s1.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_status_inspection.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_status_push_undeclared_gitlink.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_status_values.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_submodule_update_merge.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_untracked_member.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_verb_rename.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_verb_witnesses.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_store_verbs_name_their_root.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_subdir_cwd_review_verbs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_subdir_cwd_verbs.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_submodule_member_predicate.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_superproject_import.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_event_outcomes.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_fast_forward.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_fetch.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_seed_local.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_ssh_rewrite.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_sync_status_probe.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_target.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_tmux_launch_runtime.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_tracking.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_abort.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_apply.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_apply_dry_run.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_manifest_schema.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_propose.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_unit_topological_apply.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_update.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_validate_repo_path_conflict.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_version_build_stamp.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_version_identity.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_vocabulary.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_convert_clone.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_edit_lease_cap.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_identity_boundary.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_init_from_topology.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_init_local_repos.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_root_defaults.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_root_nearest_marker.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_snapshot.py +0 -0
- {gitgrip-2.0.0a11 → gitgrip-2.0.0a12}/tests/test_workspace_spec_missing.py +0 -0
|
@@ -259,6 +259,7 @@ tests/test_member_working_root_checkout_materialize.py
|
|
|
259
259
|
tests/test_merge_credential_remotes.py
|
|
260
260
|
tests/test_merge_evidence.py
|
|
261
261
|
tests/test_merge_parent_verification.py
|
|
262
|
+
tests/test_migrate_gr1_member_origin.py
|
|
262
263
|
tests/test_migrate_gr1_one_root.py
|
|
263
264
|
tests/test_migration.py
|
|
264
265
|
tests/test_migration_overlay_compatibility.py
|
|
@@ -294,6 +295,7 @@ tests/test_overlay_tier_b_repo_state.py
|
|
|
294
295
|
tests/test_overlay_tier_b_staging_discipline.py
|
|
295
296
|
tests/test_overlay_trust_model.py
|
|
296
297
|
tests/test_overlay_workspace_spec.py
|
|
298
|
+
tests/test_pin_rewind_shallow_path_quoted.py
|
|
297
299
|
tests/test_platform_adapter_changelog.py
|
|
298
300
|
tests/test_platform_adapter_plugins.py
|
|
299
301
|
tests/test_pr_adapter_v2_target.py
|
|
@@ -306,6 +308,7 @@ tests/test_pr_merge_missing_target.py
|
|
|
306
308
|
tests/test_pr_merge_partial_failure.py
|
|
307
309
|
tests/test_pr_review_subject.py
|
|
308
310
|
tests/test_pr_view.py
|
|
311
|
+
tests/test_printed_command_values_quoted.py
|
|
309
312
|
tests/test_project_file_materialization.py
|
|
310
313
|
tests/test_project_review_range_reconstruction.py
|
|
311
314
|
tests/test_project_review_three_repo.py
|
|
@@ -364,6 +367,7 @@ tests/test_review_merge_platform.py
|
|
|
364
367
|
tests/test_review_merge_receipt.py
|
|
365
368
|
tests/test_review_merge_set_alone.py
|
|
366
369
|
tests/test_review_merge_set_required.py
|
|
370
|
+
tests/test_review_merge_tracking_command_quoted.py
|
|
367
371
|
tests/test_review_merge_updates_tracking_ref.py
|
|
368
372
|
tests/test_review_named_refusals.py
|
|
369
373
|
tests/test_review_open_lane.py
|
|
@@ -421,6 +425,7 @@ tests/test_snapshot_id_prefix_resolution.py
|
|
|
421
425
|
tests/test_spec_apply_event_outcomes.py
|
|
422
426
|
tests/test_spec_declaration_ref_pin.py
|
|
423
427
|
tests/test_spec_show_native_root.py
|
|
428
|
+
tests/test_spec_sourced_git_lines_quoted.py
|
|
424
429
|
tests/test_sprint21_sync_platform.py
|
|
425
430
|
tests/test_staging_cleanup.py
|
|
426
431
|
tests/test_store_break_attempts.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"commit": "8c58df6", "release": true}
|
|
@@ -1678,7 +1678,7 @@ def workspace_init(
|
|
|
1678
1678
|
lines.append("no origin: materialize refuses these repos until a url is set:")
|
|
1679
1679
|
for repo in without_url:
|
|
1680
1680
|
lines.append(
|
|
1681
|
-
f"- {repo['name']}: git -C {workspace_root / repo['path']} "
|
|
1681
|
+
f"- {repo['name']}: git -C {next_steps._shown(workspace_root / repo['path'])} "
|
|
1682
1682
|
"remote add origin <url>"
|
|
1683
1683
|
)
|
|
1684
1684
|
typer.echo("\n".join(lines))
|
|
@@ -2087,7 +2087,7 @@ def _lane_member_branch_in(workspace_root: Path, repo_top: Path) -> tuple[str, s
|
|
|
2087
2087
|
if key is not None:
|
|
2088
2088
|
# A native workspace lane materializes every member of the selected workspace commit, which can
|
|
2089
2089
|
# differ from this lane's repos once the store grows: name no --repos there, so lane create takes them all.
|
|
2090
|
-
repos = "" if grip._is_native_workspace(workspace_root) else f" --repos {key}"
|
|
2090
|
+
repos = "" if grip._is_native_workspace(workspace_root) else f" --repos {next_steps._shown(key)}"
|
|
2091
2091
|
return unit, lane_name, key, str(branch_map.get(key) or lane_name), repos
|
|
2092
2092
|
return None
|
|
2093
2093
|
|
|
@@ -2128,9 +2128,9 @@ def _refuse_branching_a_lane_member(target: Path, name: str) -> None:
|
|
|
2128
2128
|
if name == lane_branch:
|
|
2129
2129
|
return
|
|
2130
2130
|
typer.echo(
|
|
2131
|
-
f"Error: {key} is a repo of lane {unit}/{lane_name}, whose branch for it is '{lane_branch}'; "
|
|
2131
|
+
f"Error: {key} is a repo of lane {next_steps._shown(f'{unit}/{lane_name}')}, whose branch for it is '{lane_branch}'; "
|
|
2132
2132
|
f"'{name}' was not created or switched to. The lane records its branch and fork base, so work on "
|
|
2133
|
-
f"another branch belongs in a new lane: gr2 lane create <workspace> {unit} <lane>{repos} "
|
|
2133
|
+
f"another branch belongs in a new lane: gr2 lane create <workspace> {next_steps._shown(unit)} <lane>{repos} "
|
|
2134
2134
|
f"--branch {name}",
|
|
2135
2135
|
err=True,
|
|
2136
2136
|
)
|
|
@@ -2788,12 +2788,12 @@ def repo_status(
|
|
|
2788
2788
|
if state == "changed":
|
|
2789
2789
|
hook_lines.append(
|
|
2790
2790
|
f"hooks changed since grant {getattr(target, 'name', target.path.name)} "
|
|
2791
|
-
f"(sha {hooks_sha(target.path)[:12]}) — re-bind: gr2 hooks trust {getattr(target, 'name', target.path.name)}"
|
|
2791
|
+
f"(sha {hooks_sha(target.path)[:12]}) — re-bind: gr2 hooks trust {next_steps._shown(getattr(target, 'name', target.path.name))}"
|
|
2792
2792
|
)
|
|
2793
2793
|
else:
|
|
2794
2794
|
hook_lines.append(
|
|
2795
2795
|
f"hooks unbound {getattr(target, 'name', target.path.name)} "
|
|
2796
|
-
f"(sha {hooks_sha(target.path)[:12]}) — bind: gr2 hooks trust {getattr(target, 'name', target.path.name)}"
|
|
2796
|
+
f"(sha {hooks_sha(target.path)[:12]}) — bind: gr2 hooks trust {next_steps._shown(getattr(target, 'name', target.path.name))}"
|
|
2797
2797
|
)
|
|
2798
2798
|
|
|
2799
2799
|
if json_output:
|
|
@@ -2967,9 +2967,9 @@ def hooks_status(
|
|
|
2967
2967
|
if row["state"] == "bound":
|
|
2968
2968
|
typer.echo(f"hooks bound {row['member']} (sha {row['hooks_sha']}, granted {row['granted_at']})")
|
|
2969
2969
|
elif row["state"] == "changed":
|
|
2970
|
-
typer.echo(f"hooks changed since grant {row['member']} (now sha {row['hooks_sha']}) — re-bind: gr2 hooks trust {row['member']}")
|
|
2970
|
+
typer.echo(f"hooks changed since grant {row['member']} (now sha {row['hooks_sha']}) — re-bind: gr2 hooks trust {next_steps._shown(row['member'])}")
|
|
2971
2971
|
else:
|
|
2972
|
-
typer.echo(f"hooks unbound {row['member']} (sha {row['hooks_sha']}) — bind: gr2 hooks trust {row['member']}")
|
|
2972
|
+
typer.echo(f"hooks unbound {row['member']} (sha {row['hooks_sha']}) — bind: gr2 hooks trust {next_steps._shown(row['member'])}")
|
|
2973
2973
|
|
|
2974
2974
|
|
|
2975
2975
|
@hooks_app.command("show")
|
|
@@ -4219,7 +4219,7 @@ def review_read_pr(
|
|
|
4219
4219
|
typer.echo(f"base {opened.base}")
|
|
4220
4220
|
if opened.stat:
|
|
4221
4221
|
typer.echo(opened.stat)
|
|
4222
|
-
typer.echo(f"Read the full diff: git -C {opened.path} diff {opened.base}...{opened.head}")
|
|
4222
|
+
typer.echo(f"Read the full diff: git -C {next_steps._shown(opened.path)} diff {next_steps._shown(f'{opened.base}...{opened.head}')}")
|
|
4223
4223
|
|
|
4224
4224
|
|
|
4225
4225
|
class _ReviewSelectRefused(typer.BadParameter):
|
|
@@ -16,6 +16,7 @@ from datetime import datetime, timezone
|
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
18
|
from . import approval_schema, gitops, grip
|
|
19
|
+
from .next_steps import _shown
|
|
19
20
|
|
|
20
21
|
PREFIX = "refs/dev.synapt.grip/__approvals__/v1/"
|
|
21
22
|
SCHEMA = approval_schema.PACKAGE
|
|
@@ -151,14 +152,14 @@ def review_open_lane(lane: Path) -> tuple[Path, str, dict[str, Path]] | None:
|
|
|
151
152
|
raise ApprovalRefused(f"approval_lane_names_no_workspace: {lane} was opened by an older gr2 and does not name "
|
|
152
153
|
"the workspace it was opened from",
|
|
153
154
|
next_step=f"next: open the review again, then stamp the new lane: "
|
|
154
|
-
f"gr2 review open <your-workspace> gr:
|
|
155
|
+
f"gr2 review open <your-workspace> {_shown('gr:' + str(marker['gr_commit']))} --lane-dir <new-lane>, "
|
|
155
156
|
"then gr2 review stamp <new-lane>")
|
|
156
157
|
if not Path(marker["workspace_root"]).is_absolute():
|
|
157
158
|
raise ApprovalRefused(f"approval_lane_workspace_not_absolute: {lane} names the workspace "
|
|
158
159
|
f"{marker['workspace_root']!r}, which is not absolute and would resolve against the "
|
|
159
160
|
"current directory; review open writes it absolute, so this marker was edited by hand or written elsewhere",
|
|
160
161
|
next_step=f"next: open the review again, then stamp the new lane: "
|
|
161
|
-
f"gr2 review open <your-workspace> gr:
|
|
162
|
+
f"gr2 review open <your-workspace> {_shown('gr:' + str(marker['gr_commit']))} --lane-dir <new-lane>, "
|
|
162
163
|
"then gr2 review stamp <new-lane>")
|
|
163
164
|
try:
|
|
164
165
|
members = ({rows[0]["key"]: lane} if len(rows) == 1
|
|
@@ -190,11 +191,12 @@ def _context(workspace: Path, review_id: str, member_dirs: dict[str, Path] | Non
|
|
|
190
191
|
repo = member_dirs.get(m["key"])
|
|
191
192
|
if repo is None:
|
|
192
193
|
keys = [r["key"] for r in view["members"]]
|
|
194
|
+
from . import next_steps
|
|
193
195
|
raise ApprovalRefused(
|
|
194
196
|
f"approval_lane_partial: this lane holds {', '.join(sorted(member_dirs))}; the review has "
|
|
195
197
|
f"{', '.join(keys)}",
|
|
196
|
-
next_step=f"next: open the whole review and stamp that lane: gr2 review open {workspace} "
|
|
197
|
-
f"gr:
|
|
198
|
+
next_step=f"next: open the whole review and stamp that lane: gr2 review open {next_steps._shown(workspace)} "
|
|
199
|
+
f"{next_steps._shown('gr:' + rid)} --lane-dir <new-lane>, then gr2 review stamp <new-lane>")
|
|
198
200
|
if merge_gate._toplevel(repo) != repo.resolve():
|
|
199
201
|
raise ApprovalRefused(f"approval_member_repo_mismatch: {m['key']}")
|
|
200
202
|
repo = repo.resolve()
|
|
@@ -48,7 +48,7 @@ import time
|
|
|
48
48
|
import urllib.parse
|
|
49
49
|
from pathlib import Path
|
|
50
50
|
|
|
51
|
-
from . import gitops
|
|
51
|
+
from . import gitops, next_steps
|
|
52
52
|
from .spec_apply import (
|
|
53
53
|
MaterializationPlanError,
|
|
54
54
|
ValidatedPlan,
|
|
@@ -972,7 +972,7 @@ def _reuse_existing_lane(
|
|
|
972
972
|
raise CloneExecutionError(
|
|
973
973
|
f"existing lane at {dest} is on branch {actual_branch!r}, not the expected "
|
|
974
974
|
f"{expected_branch!r}. Materialization never switches a lane's branch; move "
|
|
975
|
-
f"it back with `git -C {dest} checkout {expected_branch}` or remove the lane "
|
|
975
|
+
f"it back with `git -C {next_steps._shown(dest)} checkout {next_steps._shown(expected_branch)}` or remove the lane "
|
|
976
976
|
"to re-materialize (grip#807 step 6)"
|
|
977
977
|
)
|
|
978
978
|
if expected_seed is not None and actual_head != expected_seed:
|
|
@@ -4,6 +4,8 @@ import os
|
|
|
4
4
|
import subprocess
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
from . import next_steps
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
_SSH_GITHUB_PREFIX = "git@github.com:"
|
|
9
11
|
_HTTPS_GITHUB_PREFIX = "https://github.com/"
|
|
@@ -588,7 +590,7 @@ def checkout_declared_pin(repo_root: Path, pin: str, *, member: str) -> None:
|
|
|
588
590
|
raise SystemExit(
|
|
589
591
|
f"member '{member}' declares pin {pin}, the clone cannot reach that commit, and "
|
|
590
592
|
f"fetching it by sha from origin did not provide it. Try "
|
|
591
|
-
f"`git -C {repo_root} fetch --depth 1 origin -- {pin}` by hand to see why. This verb "
|
|
593
|
+
f"`git -C {next_steps._shown(repo_root)} fetch --depth 1 origin -- {next_steps._shown(pin)}` by hand to see why. This verb "
|
|
592
594
|
"will not leave the member on its default branch instead: that is a commit the "
|
|
593
595
|
"root never declared."
|
|
594
596
|
)
|
|
@@ -591,13 +591,13 @@ def _register_submodules(root: Path, paths: list[str]) -> None:
|
|
|
591
591
|
done = _store_git(root, "submodule", "init", "--", path, check=False)
|
|
592
592
|
if done.returncode:
|
|
593
593
|
typer.echo(f"{path}: not registered as a submodule ({_git_detail(done)}); plain `git submodule` verbs "
|
|
594
|
-
f"need `git submodule init {path}` first", err=True)
|
|
594
|
+
f"need `git submodule init -- {next_steps._shown(path)}` first", err=True)
|
|
595
595
|
continue
|
|
596
596
|
now = _registered_submodule_urls(root)
|
|
597
597
|
new, registered = now - registered, now
|
|
598
598
|
if new:
|
|
599
599
|
typer.echo(f"{path}: registered as a submodule, so plain `git submodule` verbs act on it "
|
|
600
|
-
f"(`git submodule deinit {path}` lasts until the next store commit)", err=True)
|
|
600
|
+
f"(`git submodule deinit -- {next_steps._shown(path)}` lasts until the next store commit)", err=True)
|
|
601
601
|
|
|
602
602
|
|
|
603
603
|
def _existing_sets(root: Path) -> list[dict]:
|
|
@@ -2013,7 +2013,7 @@ def _refuse_pin_rewind(
|
|
|
2013
2013
|
# says nothing about direction there; materialize would be the wrong advice for a checkout ahead.
|
|
2014
2014
|
raise PinRewindRefusal(
|
|
2015
2015
|
f"{name}: cannot tell whether HEAD {head[:12]} is behind the recorded pin {recorded[:12]}: this "
|
|
2016
|
-
f"checkout is shallow and does not reach it; run `git fetch --unshallow` in {member['path']} and "
|
|
2016
|
+
f"checkout is shallow and does not reach it; run `git fetch --unshallow` in {next_steps._shown(member['path'])} and "
|
|
2017
2017
|
f"commit again, or {allow} to record HEAD anyway",
|
|
2018
2018
|
3,
|
|
2019
2019
|
)
|
|
@@ -3831,7 +3831,7 @@ def grip_materialize_cmd(
|
|
|
3831
3831
|
if member["branch"] is None:
|
|
3832
3832
|
typer.echo(
|
|
3833
3833
|
f"{member['name']}: left detached at {member['pin'][:12]}: {member['detached']}; "
|
|
3834
|
-
f"to work on a branch: git -C {member['path']} switch -c <branch>",
|
|
3834
|
+
f"to work on a branch: git -C {next_steps._shown(member['path'])} switch -c <branch>",
|
|
3835
3835
|
err=True,
|
|
3836
3836
|
)
|
|
3837
3837
|
# stderr in both modes, so neither stdout contract moves
|
|
@@ -9,6 +9,7 @@ import tomllib
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
11
|
from .events import EventType, emit, emit_after_outcome
|
|
12
|
+
from .next_steps import _shown
|
|
12
13
|
from . import gitops
|
|
13
14
|
|
|
14
15
|
|
|
@@ -844,7 +845,7 @@ def _report_unbound(
|
|
|
844
845
|
+ ", ".join(ignored)
|
|
845
846
|
+ " — consent is a local record on the host, never inside the hooks table"
|
|
846
847
|
)
|
|
847
|
-
print(f"bind: gr2 hooks trust {ctx.repo_name}")
|
|
848
|
+
print(f"bind: gr2 hooks trust {_shown(ctx.repo_name)}")
|
|
848
849
|
|
|
849
850
|
|
|
850
851
|
def run_lifecycle_stage(
|
|
@@ -111,11 +111,15 @@ def _refresh_tracking(repo: Path, remote: str, into: str) -> dict | None:
|
|
|
111
111
|
name = next((n for n in names if urls[n] and _url_key(urls[n], repo) == want), None)
|
|
112
112
|
if name is None:
|
|
113
113
|
target = "origin" if "origin" in names else names[0]
|
|
114
|
-
|
|
114
|
+
shown = next_steps._shown # every value quoted whole: a refname may hold ';', so the line runs as printed
|
|
115
|
+
return {"command": f"git -C {shown(repo)} fetch --no-tags --refmap= -- {shown(remote)} "
|
|
116
|
+
f"{shown(f'+refs/heads/{into}:refs/remotes/{target}/{into}')}",
|
|
115
117
|
"reason": f"no remote of this clone names {remote}"}
|
|
116
118
|
spec = f"+refs/heads/{into}:refs/remotes/{name}/{into}"
|
|
117
119
|
proc = gitops.run(repo, "fetch", "--no-tags", "-q", "--refmap=", name, spec, timeout=120)
|
|
118
|
-
|
|
120
|
+
shown = next_steps._shown
|
|
121
|
+
return None if proc.returncode == 0 else {"command": f"git -C {shown(repo)} fetch --no-tags --refmap= -- {shown(name)} "
|
|
122
|
+
f"{shown(spec)}",
|
|
119
123
|
"reason": "the fetch failed"}
|
|
120
124
|
|
|
121
125
|
|
|
@@ -652,7 +656,8 @@ def review_merge(workspace: Path, review_id: str, *, into: str = "main", feature
|
|
|
652
656
|
try:
|
|
653
657
|
failed = _refresh_tracking(repo, m["remote"], into)
|
|
654
658
|
except (RuntimeError, subprocess.SubprocessError, OSError) as exc:
|
|
655
|
-
|
|
659
|
+
spec = next_steps._shown(f"+refs/heads/{into}:refs/remotes/<remote>/{into}")
|
|
660
|
+
failed = {"command": f"git -C {next_steps._shown(repo)} fetch --no-tags <remote> {spec}",
|
|
656
661
|
"reason": f"the clone could not be read: {exc}"}
|
|
657
662
|
if failed:
|
|
658
663
|
tracking_stale.append({"member": m["key"], **failed})
|
|
@@ -11,11 +11,12 @@ import tempfile
|
|
|
11
11
|
import tomllib
|
|
12
12
|
import contextlib
|
|
13
13
|
from pathlib import Path, PurePosixPath, PureWindowsPath
|
|
14
|
+
from urllib.parse import urlsplit, urlunsplit
|
|
14
15
|
|
|
15
16
|
import yaml
|
|
16
17
|
|
|
17
18
|
from . import grip
|
|
18
|
-
from .gitops import git
|
|
19
|
+
from .gitops import git, remote_origin_url
|
|
19
20
|
from .workspace_guidance import GR1_ONLY_NEXT_STEP, init_unless_inside_workspace, workspace_init_command
|
|
20
21
|
from gr2.prototypes import lane_workspace_prototype as lane_proto
|
|
21
22
|
from gr2.prototypes import repo_maintenance_prototype as repo_proto
|
|
@@ -117,6 +118,7 @@ def migrate_gr1_workspace(
|
|
|
117
118
|
"unit_count": len(compiled["units"]),
|
|
118
119
|
"snapshots": snapshots,
|
|
119
120
|
"not_migrated": list(compiled.get("not_migrated") or []),
|
|
121
|
+
"member_origins": list(compiled.get("member_origins") or []),
|
|
120
122
|
}
|
|
121
123
|
summary_path.write_text(json.dumps(summary, indent=2) + "\n")
|
|
122
124
|
|
|
@@ -794,6 +796,33 @@ def _rollback_bootstrap(
|
|
|
794
796
|
shutil.rmtree(grip_dir)
|
|
795
797
|
|
|
796
798
|
|
|
799
|
+
def _member_checkout_origin(workspace_root: Path, member_path: str) -> str | None:
|
|
800
|
+
"""The origin url of the checkout at a member's path, when that path is a repository of its own.
|
|
801
|
+
|
|
802
|
+
A path with no `.git` of its own is not the member's checkout: inside a root that is itself a
|
|
803
|
+
repository, asking git there would answer with the ROOT's origin.
|
|
804
|
+
"""
|
|
805
|
+
checkout = workspace_root / member_path
|
|
806
|
+
if not (checkout / ".git").exists():
|
|
807
|
+
return None
|
|
808
|
+
return remote_origin_url(checkout)
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
_SSH_SCHEMES = frozenset({"ssh", "git+ssh", "ssh+git"})
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
def _strip_url_userinfo(url: str) -> str:
|
|
815
|
+
"""The url without its userinfo, except an SSH login (`ssh://git@host/...`), which names an account and
|
|
816
|
+
holds no secret. An scp-like `git@host:path` has no scheme and is returned as written."""
|
|
817
|
+
try:
|
|
818
|
+
parts = urlsplit(url)
|
|
819
|
+
except ValueError:
|
|
820
|
+
return url
|
|
821
|
+
if "@" not in parts.netloc or parts.scheme.lower() in _SSH_SCHEMES:
|
|
822
|
+
return url
|
|
823
|
+
return urlunsplit(parts._replace(netloc=parts.netloc.rpartition("@")[2]))
|
|
824
|
+
|
|
825
|
+
|
|
797
826
|
def compile_gr1_to_workspace_spec(
|
|
798
827
|
workspace_root: Path,
|
|
799
828
|
manifest: dict[str, object],
|
|
@@ -806,6 +835,7 @@ def compile_gr1_to_workspace_spec(
|
|
|
806
835
|
raise ValueError("canonical gripspace manifest repos must be a mapping")
|
|
807
836
|
repos: list[dict[str, object]] = []
|
|
808
837
|
writable_repo_names: list[str] = []
|
|
838
|
+
member_origins: list[dict[str, str]] = []
|
|
809
839
|
|
|
810
840
|
for repo_name, repo_doc in repos_doc.items():
|
|
811
841
|
safe_repo_name = _safe_workspace_component(repo_name, "repo name")
|
|
@@ -813,10 +843,30 @@ def compile_gr1_to_workspace_spec(
|
|
|
813
843
|
raise ValueError(f"repository {safe_repo_name!r} must be a mapping")
|
|
814
844
|
path = repo_doc.get("path", "")
|
|
815
845
|
normalized_path = _safe_workspace_relative_path(path, f"repository {safe_repo_name!r} path")
|
|
846
|
+
manifest_url = str(repo_doc.get("url", "")).strip()
|
|
847
|
+
# The checkout at the member's path is what this desk actually fetches from; the manifest's url
|
|
848
|
+
# is what it said when the repo was added, and the two drift (a renamed repo, an SSH url, a fork).
|
|
849
|
+
checkout_url = _member_checkout_origin(workspace_root, normalized_path)
|
|
850
|
+
url = manifest_url
|
|
851
|
+
if checkout_url is not None:
|
|
852
|
+
# A credential never leaves the checkout's own git config: userinfo is stripped, and an origin that
|
|
853
|
+
# still carries one (a token in the query, a fragment) is not used and not printed.
|
|
854
|
+
checkout_url = _strip_url_userinfo(checkout_url)
|
|
855
|
+
if grip.url_has_credentials(checkout_url):
|
|
856
|
+
member_origins.append(
|
|
857
|
+
{"repo": safe_repo_name, "manifest_url": manifest_url, "checkout_url": None,
|
|
858
|
+
"refused": "credentials"}
|
|
859
|
+
)
|
|
860
|
+
else:
|
|
861
|
+
url = checkout_url
|
|
862
|
+
if checkout_url != manifest_url:
|
|
863
|
+
member_origins.append(
|
|
864
|
+
{"repo": safe_repo_name, "manifest_url": manifest_url, "checkout_url": checkout_url}
|
|
865
|
+
)
|
|
816
866
|
repo_item = {
|
|
817
867
|
"name": safe_repo_name,
|
|
818
868
|
"path": normalized_path,
|
|
819
|
-
"url":
|
|
869
|
+
"url": url,
|
|
820
870
|
}
|
|
821
871
|
if "revision" in repo_doc:
|
|
822
872
|
repo_item["default_branch"] = str(repo_doc.get("revision") or "").strip()
|
|
@@ -859,6 +909,7 @@ def compile_gr1_to_workspace_spec(
|
|
|
859
909
|
"repos": repos,
|
|
860
910
|
"units": units,
|
|
861
911
|
"not_migrated": not_migrated,
|
|
912
|
+
"member_origins": member_origins,
|
|
862
913
|
"workspace_constraints": {
|
|
863
914
|
"migration_source": "gr1",
|
|
864
915
|
},
|
|
@@ -1067,30 +1118,46 @@ def preserve_gr1_state(workspace_root: Path, migration_dir: Path) -> dict[str, s
|
|
|
1067
1118
|
return snapshots
|
|
1068
1119
|
|
|
1069
1120
|
|
|
1121
|
+
def _toml_str(value: object) -> str:
|
|
1122
|
+
"""A TOML basic string holding exactly `value`: a quote, backslash, newline or other control character in a url
|
|
1123
|
+
or name stays data. Only what TOML requires is escaped (the quote, the backslash, U+0000..U+001F and U+007F);
|
|
1124
|
+
everything else is written literally, since TOML is UTF-8 and an escaped surrogate pair (what an ASCII-only
|
|
1125
|
+
JSON string makes of a character above U+FFFF) is not a value TOML will load."""
|
|
1126
|
+
out = []
|
|
1127
|
+
for ch in str(value):
|
|
1128
|
+
if ch in ('"', "\\"):
|
|
1129
|
+
out.append("\\" + ch)
|
|
1130
|
+
elif ord(ch) < 0x20 or ord(ch) == 0x7F:
|
|
1131
|
+
out.append(f"\\u{ord(ch):04X}")
|
|
1132
|
+
else:
|
|
1133
|
+
out.append(ch)
|
|
1134
|
+
return '"' + "".join(out) + '"'
|
|
1135
|
+
|
|
1136
|
+
|
|
1070
1137
|
def render_workspace_spec(compiled: dict[str, object]) -> str:
|
|
1071
1138
|
lines = [
|
|
1072
|
-
f'workspace_name =
|
|
1139
|
+
f'workspace_name = {_toml_str(compiled["workspace_name"])}',
|
|
1073
1140
|
"",
|
|
1074
1141
|
]
|
|
1075
1142
|
constraints = compiled.get("workspace_constraints") or {}
|
|
1076
1143
|
if constraints:
|
|
1077
1144
|
lines.append("[workspace_constraints]")
|
|
1078
1145
|
for key, value in constraints.items():
|
|
1079
|
-
lines.append(f'{key} =
|
|
1146
|
+
lines.append(f'{key} = {_toml_str(value)}')
|
|
1080
1147
|
lines.append("")
|
|
1081
1148
|
|
|
1082
1149
|
for repo in compiled["repos"]:
|
|
1083
1150
|
lines.extend(
|
|
1084
1151
|
[
|
|
1085
1152
|
"[[repos]]",
|
|
1086
|
-
f'name =
|
|
1087
|
-
f'path =
|
|
1088
|
-
f'url =
|
|
1153
|
+
f'name = {_toml_str(repo["name"])}',
|
|
1154
|
+
f'path = {_toml_str(repo["path"])}',
|
|
1155
|
+
f'url = {_toml_str(repo["url"])}',
|
|
1089
1156
|
]
|
|
1090
1157
|
)
|
|
1091
1158
|
default_branch = str(repo.get("default_branch", "")).strip()
|
|
1092
1159
|
if default_branch:
|
|
1093
|
-
lines.append(f'default_branch =
|
|
1160
|
+
lines.append(f'default_branch = {_toml_str(default_branch)}')
|
|
1094
1161
|
if repo.get("reference", False):
|
|
1095
1162
|
lines.append("reference = true")
|
|
1096
1163
|
lines.append("")
|
|
@@ -1099,9 +1166,9 @@ def render_workspace_spec(compiled: dict[str, object]) -> str:
|
|
|
1099
1166
|
lines.extend(
|
|
1100
1167
|
[
|
|
1101
1168
|
"[[units]]",
|
|
1102
|
-
f'name =
|
|
1103
|
-
f'path =
|
|
1104
|
-
"repos = [" + ", ".join(
|
|
1169
|
+
f'name = {_toml_str(unit["name"])}',
|
|
1170
|
+
f'path = {_toml_str(unit["path"])}',
|
|
1171
|
+
"repos = [" + ", ".join(_toml_str(repo) for repo in unit["repos"]) + "]",
|
|
1105
1172
|
]
|
|
1106
1173
|
)
|
|
1107
1174
|
lines.append("")
|
|
@@ -1147,6 +1214,25 @@ def render_migration(payload: dict[str, object]) -> str:
|
|
|
1147
1214
|
f"{len(not_migrated)} unit(s) in the gr1 agents manifest are not in this workspace's spec,"
|
|
1148
1215
|
" and nothing under them was read. A desk that is its own root migrates from that root."
|
|
1149
1216
|
)
|
|
1217
|
+
member_origins = payload.get("member_origins") or []
|
|
1218
|
+
if member_origins:
|
|
1219
|
+
lines.append("MEMBER ORIGIN")
|
|
1220
|
+
for row in member_origins:
|
|
1221
|
+
if row.get("refused") == "credentials":
|
|
1222
|
+
lines.append(
|
|
1223
|
+
f"- {_printable(row['repo'])}: the checkout's origin carries credentials or cannot be parsed and"
|
|
1224
|
+
" was not used;"
|
|
1225
|
+
f" the spec keeps {_printable(row['manifest_url'])}. Remove the credential from the url and use a"
|
|
1226
|
+
" credential helper."
|
|
1227
|
+
)
|
|
1228
|
+
continue
|
|
1229
|
+
lines.append(
|
|
1230
|
+
f"- {_printable(row['repo'])}: {_printable(row['manifest_url'])} -> {_printable(row['checkout_url'])}"
|
|
1231
|
+
)
|
|
1232
|
+
lines.append(
|
|
1233
|
+
f"{len(member_origins)} member(s) differ from the gr1 manifest; the spec records each checkout's own"
|
|
1234
|
+
" origin (userinfo removed), which is what this desk fetches from."
|
|
1235
|
+
)
|
|
1150
1236
|
lines.append("SNAPSHOTS")
|
|
1151
1237
|
lines.extend(f"- {name}\t{path}" for name, path in payload["snapshots"].items())
|
|
1152
1238
|
return "\n".join(lines)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from .layout import grip_dir
|
|
6
|
+
from .next_steps import _shown
|
|
6
7
|
|
|
7
8
|
GR1_ONLY_NEXT_STEP = (
|
|
8
9
|
"This workspace is still in gr1 format. Run `gr2 workspace migrate-gr1 .` "
|
|
@@ -51,7 +52,7 @@ def missing_workspace_spec_message(workspace_root: Path) -> str:
|
|
|
51
52
|
def workspace_init_command(target: object = "") -> str:
|
|
52
53
|
"""The one place a verb's advice spells the init command (a structural test holds every other text to it), so
|
|
53
54
|
whether that advice suits the path is decided once, in `init_unless_inside_workspace`."""
|
|
54
|
-
return f"`gr2 workspace init {target}`" if str(target) else "`gr2 workspace init`"
|
|
55
|
+
return f"`gr2 workspace init {_shown(target)}`" if str(target) else "`gr2 workspace init`"
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
def inside_workspace_sentence(path: Path, enclosing: Path) -> str:
|
|
@@ -11,7 +11,7 @@ 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.
|
|
14
|
+
version = "2.0.0a12"
|
|
15
15
|
description = "Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice"
|
|
16
16
|
readme = "README.md"
|
|
17
17
|
requires-python = ">=3.11"
|
|
@@ -388,3 +388,54 @@ def test_an_unloadable_bound_lane_without_a_usable_worktree_does_not_hold_its_la
|
|
|
388
388
|
made = _branch(repo, "other")
|
|
389
389
|
assert made.exit_code == 0, made.output
|
|
390
390
|
assert _git(repo, "branch", "--show-current") == "other"
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def test_the_lane_named_in_the_refusal_is_quoted_when_its_directories_hold_shell_text(tmp_path: Path) -> None:
|
|
394
|
+
# Rule: the unit and lane come from the lane doc's directory names, not from the person typing `gr2 branch`,
|
|
395
|
+
# so the printed lane create quotes them: shlex.split gives the unit as one argument, and the line run by a
|
|
396
|
+
# shell (gr2 stubbed) starts nothing the directory names hold.
|
|
397
|
+
from gr2.prototypes import lane_workspace_prototype as lanes
|
|
398
|
+
import subprocess
|
|
399
|
+
|
|
400
|
+
ws, _repos = _lane(tmp_path)
|
|
401
|
+
repo = _plain(ws / "solo-repo")
|
|
402
|
+
unit, lane = "u; touch MARKU", "l; touch MARKL"
|
|
403
|
+
path = lanes.lane_file(ws, unit, lane)
|
|
404
|
+
path.parent.mkdir(parents=True)
|
|
405
|
+
path.write_text(f'lane_kind = "bound"\nrepos = ["solo"]\nbound_worktree = "{repo}"\n')
|
|
406
|
+
moved = _branch(repo, "other")
|
|
407
|
+
assert moved.exit_code == 2, moved.output
|
|
408
|
+
assert f"lane {shlex.quote(f'{unit}/{lane}')}," in moved.output, moved.output
|
|
409
|
+
printed = moved.output.split("new lane: ", 1)[1].strip().replace("<workspace>", str(ws)).replace("<lane>", "next")
|
|
410
|
+
argv = shlex.split(printed)
|
|
411
|
+
assert argv[:6] == ["gr2", "lane", "create", str(ws), unit, "next"], printed
|
|
412
|
+
assert argv[-2:] == ["--branch", "other"], printed
|
|
413
|
+
ran = subprocess.run(["bash", "-c", "gr2() { :; }\n" + printed], cwd=tmp_path, capture_output=True, text=True)
|
|
414
|
+
assert ran.returncode == 0, ran.stderr
|
|
415
|
+
assert not (tmp_path / "MARKU").exists() and not (tmp_path / "MARKL").exists(), printed
|
|
416
|
+
assert list(tmp_path.glob("MARK*")) == [], printed
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def test_the_member_key_in_the_refusal_is_quoted_when_the_lane_record_holds_shell_text(tmp_path: Path) -> None:
|
|
420
|
+
# Rule: the `--repos` key comes from the lane record, not from the person typing `gr2 branch`, and a plain
|
|
421
|
+
# member key may hold ';' and a space (only separators, NUL and newline are refused), so the printed lane
|
|
422
|
+
# create quotes it: shlex.split gives the key as one argument, and the line run by a shell starts nothing.
|
|
423
|
+
from gr2.prototypes import lane_workspace_prototype as lanes
|
|
424
|
+
import subprocess
|
|
425
|
+
|
|
426
|
+
ws = tmp_path / "ws" # a spec workspace (no native root), where the refusal names --repos
|
|
427
|
+
(ws / ".grip").mkdir(parents=True)
|
|
428
|
+
(ws / ".grip" / "workspace_spec.toml").write_text('schema_version = 1\nworkspace_name = "m"\n')
|
|
429
|
+
repo = _plain(ws / "solo-repo")
|
|
430
|
+
key = "s; touch MARKK #"
|
|
431
|
+
path = lanes.lane_file(ws, "u", "l")
|
|
432
|
+
path.parent.mkdir(parents=True)
|
|
433
|
+
path.write_text(f'lane_kind = "bound"\nrepos = ["{key}"]\nbound_worktree = "{repo}"\n')
|
|
434
|
+
moved = _branch(repo, "other")
|
|
435
|
+
assert moved.exit_code == 2, moved.output
|
|
436
|
+
printed = moved.output.split("new lane: ", 1)[1].strip().replace("<workspace>", str(ws)).replace("<lane>", "next")
|
|
437
|
+
argv = shlex.split(printed)
|
|
438
|
+
assert argv[6:] == ["--repos", key, "--branch", "other"], printed
|
|
439
|
+
ran = subprocess.run(["bash", "-c", "gr2() { :; }\n" + printed], cwd=tmp_path, capture_output=True, text=True)
|
|
440
|
+
assert ran.returncode == 0, ran.stderr
|
|
441
|
+
assert list(tmp_path.glob("MARK*")) == [], printed
|