git-repokit 0.9.11__tar.gz → 0.9.12__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.
- {git_repokit-0.9.11/git_repokit.egg-info → git_repokit-0.9.12}/PKG-INFO +1 -3
- {git_repokit-0.9.11 → git_repokit-0.9.12}/README.md +0 -2
- {git_repokit-0.9.11 → git_repokit-0.9.12/git_repokit.egg-info}/PKG-INFO +1 -3
- {git_repokit-0.9.11 → git_repokit-0.9.12}/git_repokit.egg-info/SOURCES.txt +1 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/pyproject.toml +1 -1
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/__version__.py +1 -1
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/branch_utils.py +4 -2
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/common_kit.py +42 -5
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/guardrails.py +1 -1
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/hooks/pre-commit-template +2 -2
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/repo_manager.py +81 -77
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/hooks/pre-commit.template +2 -2
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers.py +39 -1
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_new_default.py +11 -0
- git_repokit-0.9.12/tests/test_private_branch_create.py +338 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/LICENSE +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/MANIFEST.in +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/git_repokit.egg-info/dependency_links.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/git_repokit.egg-info/entry_points.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/git_repokit.egg-info/requires.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/git_repokit.egg-info/top_level.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/__main__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/analyzer.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/backend.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/cache.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/parsers.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/transports/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/transports/cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/transports/openai_compat.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/transports/prompt_file.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/_vendor/ailib/types.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/auth_integration.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/badges.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/config.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/defaults.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/directory_analyzer.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/directory_profiles.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/git_config.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/github_create.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/github_setup.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/history_cleaner.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/history_protection.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/hooks/pre-commit-guardrails +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/layers.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/0bsd.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/LICENSES.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/agpl-3.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/all-rights-reserved.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/apache-2.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/bsd-2-clause.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/bsd-3-clause.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/bsl-1.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/cc-by-4.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/cc-by-sa-4.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/cc0-1.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/epl-2.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/gpl-2.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/gpl-3.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/isc.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/lgpl-2.1.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/lgpl-3.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/mit.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/mpl-2.0.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/proprietary-evaluation.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/licenses/unlicense.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/readme_blocks.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/remote_integration.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/template_engine.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/ai/claude/CLAUDE-nested.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/ai/claude/CLAUDE.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/ai/claude/instructions/step1_context_rebuilder.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/ai/claude/instructions/step2_dev_workflow_process.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/ai/claude/instructions/step3_context_bridge.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/common/CHANGELOG.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/common/CONTRIBUTING.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/common/README.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/common/gitattributes.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/common/gitignore.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/FUNDING.yml.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/ROADMAP.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/dependabot.yml.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/one-offs-README.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/platform-support.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/pull_request_template.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/release-template.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/settings.json.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/extras/stale.yml.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/github/CODEOWNERS.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/github/ISSUE_TEMPLATE/bug-report.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/github/ISSUE_TEMPLATE/feature-request.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/github/issues/notes.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/github/issues/roadmap.md.template +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/any/claude-plugin/.claude-plugin/marketplace.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/any/claude-plugin/plugin/.claude-plugin/plugin.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/any/claude-plugin/plugin/README.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/.github/workflows/ci-c-cpp.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/.repokit-common.toml.rkappend +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/.vscode/tasks.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/CMakeLists.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/CMakePresets.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/cmake/GenerateStamp.cmake +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/src/main.cpp +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/tests/test_version.cpp +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/cmake-app/vcpkg.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/minimal/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/minimal/Makefile +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/minimal/build.bat +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/minimal/src/__RK_SNAKE__.c +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/msbuild/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/msbuild/.vscode/tasks.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/msbuild/__RK_PROJECT__.sln +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/msbuild/__RK_PROJECT__.vcxproj +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/c-cpp/msbuild/src/main.cpp +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/claude-plugin/.repokit-common.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/claude-plugin/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/hooks/hooks.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/hooks/scripts/session-start.mjs +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/claude-plugin/plugin/tests/manifest.test.js +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node/.repokit-common.toml.rkappend +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node/package.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node-package/.github/workflows/release.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node-package/package.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node-package/src/index.ts +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/node-package/tests/index.test.ts +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/script/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/script/__RK_PROJECT__.js +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/script/tests/version.test.js +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/ts/package.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/js-ts/ts/tsconfig.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/.github/workflows/ci-python.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/.repokit-common.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/VERSION +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/hooks.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/scripts/run-hook.mjs +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/plugin/hooks/scripts/session_start.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/claude-plugin/plugin/tests/test_manifest.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/.github/workflows/release.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/__init__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/__main__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/_version.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/__RK_SNAKE__/cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/pyproject.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/tests/conftest.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/pypi/tests/test_version.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/.github/workflows/ci-python.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/.repokit-common.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/VERSION +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/__RK_PROJECT__.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/script/tests/test_version.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/setuppy/requirements.txt +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/archetypes/python/setuppy/setup.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/c-cpp/.gitignore.rkappend +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/c-cpp/.repokit-common.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/c-cpp/include/__RK_SNAKE__/version.h +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/c-cpp/src/app.rc +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/.editorconfig +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/.github/workflows/ci-js-ts.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/.gitignore.rkappend +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/.repokit-common.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/js-ts/VERSION +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/python/.github/workflows/ci-python.yml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/python/.gitignore.rkappend +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/languages/python/.vscode/launch.json +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/layers/manifest.toml +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/CLAUDE.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_maps/MOC-project.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_oracle/backlinks.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_oracle/concepts.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_oracle/manifest.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_todo/ACTIVE-WORK.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/templates/vault/claude/_todo/OPEN-LOOPS.md +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/utils.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/repokit/vault.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/setup.cfg +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/setup.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_badges.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_branch_strategies.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_cli_examples.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_cli_integration.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_core_functionality.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_deployment_scenarios.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_directory_profiles.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_docs_links.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_extras_cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_github_create.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_github_integration.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_github_owner.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_github_setup.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_guardrails.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_hermetic.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_hook_encoding.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_hook_patterns.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layer_action_pins.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_c_cpp.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_claude_plugin.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_compositions.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_js_ts.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_layers_vscode.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_legacy_smoke.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_license_adopt.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_license_cli.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_licenses.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_packaging.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_readme_blocks.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_run_tests_driver.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_template_parity.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_utils.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_vault_bootstrap.py +0 -0
- {git_repokit-0.9.11 → git_repokit-0.9.12}/tests/test_vendored_ailib.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-repokit
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.12
|
|
4
4
|
Summary: Create standardized Git repositories: language presets, licenses, GitHub setup, and a private notes vault
|
|
5
5
|
Author: Dustin Darcy
|
|
6
6
|
License-Expression: MIT
|
|
@@ -157,8 +157,6 @@ git push
|
|
|
157
157
|
|
|
158
158
|
`safe-merge` leaves out the private content (`private/`, `CLAUDE.md`, `revisions/`, ...), and the hooks refuse it on a public branch if it ever gets staged. `--github` pushes only the public branches. Other layouts: `simple` (private, dev, main), `gitflow`, `github-flow`, and your own with `--branches` and `--worktrees`; see [Branch strategies](#branch-strategies) below.
|
|
159
159
|
|
|
160
|
-
> **Known issue in 0.9.11:** this create prints `fatal: ambiguous argument 'private'` once per public branch, and `dev/` and `github/` start with only the README and `.github/`. The loop above still brings the work across. The fix is tracked in [#16](https://github.com/DazzleTools/git-repokit/issues/16).
|
|
161
|
-
|
|
162
160
|
### Other common creates
|
|
163
161
|
|
|
164
162
|
```bash
|
|
@@ -116,8 +116,6 @@ git push
|
|
|
116
116
|
|
|
117
117
|
`safe-merge` leaves out the private content (`private/`, `CLAUDE.md`, `revisions/`, ...), and the hooks refuse it on a public branch if it ever gets staged. `--github` pushes only the public branches. Other layouts: `simple` (private, dev, main), `gitflow`, `github-flow`, and your own with `--branches` and `--worktrees`; see [Branch strategies](#branch-strategies) below.
|
|
118
118
|
|
|
119
|
-
> **Known issue in 0.9.11:** this create prints `fatal: ambiguous argument 'private'` once per public branch, and `dev/` and `github/` start with only the README and `.github/`. The loop above still brings the work across. The fix is tracked in [#16](https://github.com/DazzleTools/git-repokit/issues/16).
|
|
120
|
-
|
|
121
119
|
### Other common creates
|
|
122
120
|
|
|
123
121
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-repokit
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.12
|
|
4
4
|
Summary: Create standardized Git repositories: language presets, licenses, GitHub setup, and a private notes vault
|
|
5
5
|
Author: Dustin Darcy
|
|
6
6
|
License-Expression: MIT
|
|
@@ -157,8 +157,6 @@ git push
|
|
|
157
157
|
|
|
158
158
|
`safe-merge` leaves out the private content (`private/`, `CLAUDE.md`, `revisions/`, ...), and the hooks refuse it on a public branch if it ever gets staged. `--github` pushes only the public branches. Other layouts: `simple` (private, dev, main), `gitflow`, `github-flow`, and your own with `--branches` and `--worktrees`; see [Branch strategies](#branch-strategies) below.
|
|
159
159
|
|
|
160
|
-
> **Known issue in 0.9.11:** this create prints `fatal: ambiguous argument 'private'` once per public branch, and `dev/` and `github/` start with only the README and `.github/`. The loop above still brings the work across. The fix is tracked in [#16](https://github.com/DazzleTools/git-repokit/issues/16).
|
|
161
|
-
|
|
162
160
|
### Other common creates
|
|
163
161
|
|
|
164
162
|
```bash
|
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
# PyPI's trusted publisher is registered for this name (DazzleTools/git-repokit,
|
|
9
9
|
# publish.yml, environment pypi); the command stays `repokit`
|
|
10
10
|
name = "git-repokit"
|
|
11
|
-
version = "0.9.
|
|
11
|
+
version = "0.9.12"
|
|
12
12
|
description = "Create standardized Git repositories: language presets, licenses, GitHub setup, and a private notes vault"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
license = "MIT"
|
|
@@ -154,10 +154,12 @@ class BranchContext:
|
|
|
154
154
|
return self.branch_type == 'public'
|
|
155
155
|
|
|
156
156
|
def get_staged_files(self) -> List[str]:
|
|
157
|
-
"""
|
|
157
|
+
"""Files the commit adds or changes (0.9.12: deletions are left out --
|
|
158
|
+
removing a private file from a public branch is what the guard wants,
|
|
159
|
+
not something to refuse)."""
|
|
158
160
|
try:
|
|
159
161
|
result = subprocess.run(
|
|
160
|
-
['git', 'diff', '--cached', '--name-only'],
|
|
162
|
+
['git', 'diff', '--cached', '--name-only', '--diff-filter=ACMR'],
|
|
161
163
|
cwd=self.repo_path,
|
|
162
164
|
capture_output=True,
|
|
163
165
|
text=True,
|
|
@@ -131,23 +131,59 @@ def _toml_list(values: List[str]) -> str:
|
|
|
131
131
|
_TABLE_HEADER = re.compile(r"^[ \t]*\[[ \t]*tool[ \t]*\.[ \t]*\"?repokit-common\"?[ \t]*\][ \t]*\r?\n", re.MULTILINE)
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
# Keys whose list only ever protects more as it grows: when the table already
|
|
135
|
+
# has one, the entries it lacks are added to it rather than the key being
|
|
136
|
+
# skipped (0.9.12). A layer's pyproject.toml ships its own private-patterns, and
|
|
137
|
+
# skipping the key dropped CLAUDE.md and the private dirs from the guard.
|
|
138
|
+
_UNION_KEYS = ("private-patterns",)
|
|
139
|
+
_TOML_STRING = re.compile(r'"((?:[^"\\]|\\.)*)"|\'([^\']*)\'')
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _union_into_list(table: str, key: str, values: List[str]) -> Optional[str]:
|
|
143
|
+
"""`table` with the `values` its `key = [...]` list lacks appended inside
|
|
144
|
+
the brackets (a list written over several lines is kept as written).
|
|
145
|
+
None when the key is not a list or nothing is missing."""
|
|
146
|
+
found = re.search(rf"^([ \t]*{re.escape(key)}[ \t]*=[ \t]*\[)(.*?)(\])", table, re.MULTILINE | re.DOTALL)
|
|
147
|
+
if not found:
|
|
148
|
+
return None
|
|
149
|
+
inner = found.group(2)
|
|
150
|
+
present = {(m.group(1) if m.group(1) is not None else m.group(2)).replace('\\"', '"').replace("\\\\", "\\")
|
|
151
|
+
for m in _TOML_STRING.finditer(inner)}
|
|
152
|
+
missing = [v for v in values if v not in present]
|
|
153
|
+
if not missing:
|
|
154
|
+
return None
|
|
155
|
+
kept = inner.rstrip()
|
|
156
|
+
tail = inner[len(kept):]
|
|
157
|
+
sep = "" if not kept.strip() else (" " if kept.endswith(",") else ", ")
|
|
158
|
+
added = _toml_list(missing)[1:-1]
|
|
159
|
+
return table[: found.start(2)] + kept + sep + added + tail + table[found.end(2):]
|
|
160
|
+
|
|
161
|
+
|
|
134
162
|
def _merge_into_table(text: str, settings: Dict[str, List[str]]) -> Optional[str]:
|
|
135
163
|
"""Add the keys the existing [tool.repokit-common] table lacks, right after
|
|
136
|
-
its header
|
|
137
|
-
|
|
164
|
+
its header. A key already present is never overwritten, except that a
|
|
165
|
+
`_UNION_KEYS` list gains the entries it lacks. Returns the new text, or
|
|
166
|
+
None when nothing was missing."""
|
|
138
167
|
header = _TABLE_HEADER.search(text)
|
|
139
168
|
if not header:
|
|
140
169
|
return None
|
|
141
170
|
rest = text[header.end():]
|
|
142
171
|
next_table = re.search(r"^[ \t]*\[", rest, re.MULTILINE) # the table ends at the next header
|
|
143
172
|
table = rest[: next_table.start()] if next_table else rest
|
|
173
|
+
after = rest[len(table):]
|
|
144
174
|
missing = [key for key in settings
|
|
145
175
|
if not re.search(rf"^[ \t]*{re.escape(key)}[ \t]*=", table, re.MULTILINE)]
|
|
146
|
-
|
|
176
|
+
grown = table
|
|
177
|
+
for key in _UNION_KEYS:
|
|
178
|
+
if key in settings and key not in missing:
|
|
179
|
+
unioned = _union_into_list(grown, key, settings[key])
|
|
180
|
+
if unioned is not None:
|
|
181
|
+
grown = unioned
|
|
182
|
+
if not missing and grown == table:
|
|
147
183
|
return None
|
|
148
184
|
nl = "\r\n" if "\r\n" in text else "\n"
|
|
149
185
|
lines = "".join(f"{key} = {_toml_list(settings[key])}{nl}" for key in missing)
|
|
150
|
-
return text[: header.end()] + lines +
|
|
186
|
+
return text[: header.end()] + lines + grown + after
|
|
151
187
|
|
|
152
188
|
|
|
153
189
|
def write_settings(repo_root: str, settings: Dict[str, List[str]]) -> Optional[str]:
|
|
@@ -158,7 +194,8 @@ def write_settings(repo_root: str, settings: Dict[str, List[str]]) -> Optional[s
|
|
|
158
194
|
(created with the header repokit-common requires, or merged the same way).
|
|
159
195
|
A key already present is never overwritten: a code-type layer may ship
|
|
160
196
|
the file with its own version-source, and the private-branch settings go
|
|
161
|
-
in beside it rather than being dropped.
|
|
197
|
+
in beside it rather than being dropped. The one exception is
|
|
198
|
+
private-patterns, whose existing list gains the entries it lacks.
|
|
162
199
|
"""
|
|
163
200
|
if not settings:
|
|
164
201
|
return None
|
|
@@ -214,7 +214,7 @@ except ImportError:
|
|
|
214
214
|
|
|
215
215
|
if branch not in ['private', 'local']:
|
|
216
216
|
# Check for obvious private files
|
|
217
|
-
result = subprocess.run(['git', 'diff', '--cached', '--name-only'],
|
|
217
|
+
result = subprocess.run(['git', 'diff', '--cached', '--name-only', '--diff-filter=ACMR'],
|
|
218
218
|
capture_output=True, text=True)
|
|
219
219
|
files = result.stdout.strip().split('\\n')
|
|
220
220
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Pre-commit hook to prevent committing private content
|
|
3
3
|
|
|
4
4
|
# Check for private directories
|
|
5
|
-
for file in $(git diff --cached --name-only); do
|
|
5
|
+
for file in $(git diff --cached --name-only --diff-filter=ACMR); do
|
|
6
6
|
if echo "$file" | grep -q -E "^private/|^convos/|^logs/|__private__"; then
|
|
7
7
|
echo "ERROR: Attempting to commit private content: $file"
|
|
8
8
|
echo "Private content should not be committed to the repository."
|
|
@@ -15,7 +15,7 @@ PRIVATE_PATTERNS=(
|
|
|
15
15
|
$private_dirs_patterns
|
|
16
16
|
)
|
|
17
17
|
|
|
18
|
-
for file in $(git diff --cached --name-only); do
|
|
18
|
+
for file in $(git diff --cached --name-only --diff-filter=ACMR); do
|
|
19
19
|
for pattern in "${PRIVATE_PATTERNS[@]}"; do
|
|
20
20
|
if echo "$file" | grep -q -E "$pattern"; then
|
|
21
21
|
echo "ERROR: Attempting to commit private content: $file"
|
|
@@ -239,9 +239,10 @@ class RepoManager:
|
|
|
239
239
|
# Create local repository directory
|
|
240
240
|
os.makedirs(self.repo_root, exist_ok=True)
|
|
241
241
|
|
|
242
|
-
#
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
# No <name>/github is made ahead of time (0.9.12): `git worktree add`
|
|
243
|
+
# creates the folder when main is checked out there, and a strategy
|
|
244
|
+
# with no worktree for main (minimal), or one that checks main out
|
|
245
|
+
# elsewhere (--branch-dir-main), must not get a stray github/ folder.
|
|
245
246
|
|
|
246
247
|
# Create standard subdirectories
|
|
247
248
|
standard_dirs = self.config.get(
|
|
@@ -1070,6 +1071,29 @@ class RepoManager:
|
|
|
1070
1071
|
else:
|
|
1071
1072
|
self.logger.info(f"Linked {path}/private to the private repository")
|
|
1072
1073
|
|
|
1074
|
+
def _worktree_of(self, branch: str) -> Optional[str]:
|
|
1075
|
+
"""The folder where `branch` is checked out in a worktree other than
|
|
1076
|
+
repo_root itself, from `git worktree list --porcelain`; None when it
|
|
1077
|
+
has none (0.9.12)."""
|
|
1078
|
+
out = self.run_git(["worktree", "list", "--porcelain"], cwd=self.repo_root, check=False) or ""
|
|
1079
|
+
here = os.path.normcase(os.path.abspath(self.repo_root))
|
|
1080
|
+
path = None
|
|
1081
|
+
for line in out.splitlines():
|
|
1082
|
+
if line.startswith("worktree "):
|
|
1083
|
+
path = line[len("worktree "):].strip()
|
|
1084
|
+
elif line.strip() == f"branch refs/heads/{branch}" and path:
|
|
1085
|
+
if os.path.normcase(os.path.abspath(path)) != here:
|
|
1086
|
+
return path
|
|
1087
|
+
return None
|
|
1088
|
+
|
|
1089
|
+
@staticmethod
|
|
1090
|
+
def _branch_exists_in(repo: str, name: str) -> bool:
|
|
1091
|
+
"""Whether a local branch named exactly `name` exists in `repo`
|
|
1092
|
+
(0.9.12: the old check matched by substring, so `dev` found `develop`)."""
|
|
1093
|
+
result = subprocess.run(["git", "show-ref", "--verify", "--quiet", f"refs/heads/{name}"],
|
|
1094
|
+
cwd=repo, capture_output=True, stdin=subprocess.DEVNULL)
|
|
1095
|
+
return result.returncode == 0
|
|
1096
|
+
|
|
1073
1097
|
def _setup_github_integration(self) -> None:
|
|
1074
1098
|
"""Set up GitHub integration."""
|
|
1075
1099
|
self.logger.info("Setting up GitHub integration")
|
|
@@ -1084,6 +1108,19 @@ class RepoManager:
|
|
|
1084
1108
|
if not self.github_root:
|
|
1085
1109
|
return
|
|
1086
1110
|
|
|
1111
|
+
# Run git only in the default branch's real worktree (0.9.12). The
|
|
1112
|
+
# folder is where `git worktree list` says the branch is checked out,
|
|
1113
|
+
# not an assumed <name>/github: with no worktree there, `git add` and
|
|
1114
|
+
# `git commit` walked up into whatever repository enclosed the
|
|
1115
|
+
# project and committed in it. No worktree for the default branch
|
|
1116
|
+
# means nothing to do -- the branch already carries .github, cut from
|
|
1117
|
+
# the private branch.
|
|
1118
|
+
main_worktree = self._worktree_of(self.config.get("default_branch", "main"))
|
|
1119
|
+
if not main_worktree:
|
|
1120
|
+
self.logger.info("No worktree for the default branch; its .github came with the branch")
|
|
1121
|
+
return
|
|
1122
|
+
self.github_root = main_worktree
|
|
1123
|
+
|
|
1087
1124
|
# Only proceed if the GitHub worktree exists
|
|
1088
1125
|
if not os.path.exists(self.github_root):
|
|
1089
1126
|
self.logger.warning(
|
|
@@ -1222,7 +1259,7 @@ class RepoManager:
|
|
|
1222
1259
|
# Pre-commit hook to prevent committing private content
|
|
1223
1260
|
|
|
1224
1261
|
# Check for private directories
|
|
1225
|
-
for file in $(git diff --cached --name-only); do
|
|
1262
|
+
for file in $(git diff --cached --name-only --diff-filter=ACMR); do
|
|
1226
1263
|
if echo "$file" | grep -q -E "^private/|^convos/|^logs/|__private__"; then
|
|
1227
1264
|
echo "ERROR: Attempting to commit private content: $file"
|
|
1228
1265
|
echo "Private content should not be committed to the repository."
|
|
@@ -1427,6 +1464,10 @@ exit 0
|
|
|
1427
1464
|
)
|
|
1428
1465
|
private_branch = self.private_branch
|
|
1429
1466
|
|
|
1467
|
+
# A public branch that cannot be built, or fails verification, fails
|
|
1468
|
+
# the create (0.9.12): it used to be a warning and the create exited 0
|
|
1469
|
+
# with every public branch holding only the initial commit.
|
|
1470
|
+
failed = []
|
|
1430
1471
|
for branch in branches:
|
|
1431
1472
|
if branch != private_branch: # Skip private branch
|
|
1432
1473
|
try:
|
|
@@ -1447,17 +1488,21 @@ exit 0
|
|
|
1447
1488
|
self.logger.info(f"Successfully created and verified clean public branch '{branch}'")
|
|
1448
1489
|
else:
|
|
1449
1490
|
self.logger.error(f"Branch '{branch}' failed verification - contains private content!")
|
|
1450
|
-
|
|
1491
|
+
failed.append(branch)
|
|
1492
|
+
|
|
1451
1493
|
if self.verbose >= 2:
|
|
1452
1494
|
approach = "selective" if is_adoption else "standard"
|
|
1453
1495
|
self.logger.debug(
|
|
1454
1496
|
f"Created clean public branch '{branch}' using {approach} approach"
|
|
1455
1497
|
)
|
|
1456
1498
|
except Exception as e:
|
|
1457
|
-
self.logger.
|
|
1499
|
+
self.logger.error(f"Failed to create clean public branch '{branch}': {str(e)}")
|
|
1500
|
+
failed.append(branch)
|
|
1458
1501
|
|
|
1459
1502
|
# Switch back to private branch for continued development
|
|
1460
1503
|
self.run_git(["checkout", private_branch], cwd=self.repo_root)
|
|
1504
|
+
if failed:
|
|
1505
|
+
raise RuntimeError(f"public branches not built: {', '.join(failed)}")
|
|
1461
1506
|
|
|
1462
1507
|
def _get_working_directory_files(self) -> List[str]:
|
|
1463
1508
|
"""
|
|
@@ -1575,8 +1620,7 @@ exit 0
|
|
|
1575
1620
|
current_branch = self.run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=self.repo_root).strip()
|
|
1576
1621
|
|
|
1577
1622
|
# Check if branch already exists
|
|
1578
|
-
|
|
1579
|
-
branch_exists = any(branch_name in branch.strip() for branch in existing_branches)
|
|
1623
|
+
branch_exists = self._branch_exists_in(self.repo_root, branch_name) # exact name (0.9.12)
|
|
1580
1624
|
|
|
1581
1625
|
if branch_exists:
|
|
1582
1626
|
self.logger.info(f"Branch '{branch_name}' already exists, will recreate with selective approach")
|
|
@@ -1660,17 +1704,22 @@ exit 0
|
|
|
1660
1704
|
current_branch = self.run_git(["rev-parse", "--abbrev-ref", "HEAD"], cwd=self.repo_root).strip()
|
|
1661
1705
|
|
|
1662
1706
|
# Check if branch already exists
|
|
1663
|
-
|
|
1664
|
-
branch_exists = any(branch_name in branch.strip() for branch in existing_branches)
|
|
1707
|
+
branch_exists = self._branch_exists_in(self.repo_root, branch_name) # exact name (0.9.12)
|
|
1665
1708
|
|
|
1709
|
+
# The source is always the BRANCH, never a folder of the same name:
|
|
1710
|
+
# a private/ folder sits beside the private branch, and a bare
|
|
1711
|
+
# `git reset --hard private` is refused as ambiguous (0.9.12;
|
|
1712
|
+
# djdarcy: "The only private we care about in the private-public
|
|
1713
|
+
# branch strategy is the "private" branch as the source").
|
|
1714
|
+
source_ref = f"refs/heads/{source_branch}"
|
|
1666
1715
|
if branch_exists:
|
|
1667
1716
|
# Branch exists, check it out and reset it
|
|
1668
1717
|
self.logger.info(f"Branch '{branch_name}' already exists, resetting it")
|
|
1669
1718
|
self.run_git(["checkout", branch_name], cwd=self.repo_root)
|
|
1670
|
-
self.run_git(["reset", "--hard",
|
|
1719
|
+
self.run_git(["reset", "--hard", source_ref], cwd=self.repo_root)
|
|
1671
1720
|
else:
|
|
1672
1721
|
# Create the new branch from the source branch
|
|
1673
|
-
self.run_git(["checkout", "-b", branch_name,
|
|
1722
|
+
self.run_git(["checkout", "-b", branch_name, source_ref], cwd=self.repo_root)
|
|
1674
1723
|
|
|
1675
1724
|
# Use existing BranchContext with configuration to identify private content
|
|
1676
1725
|
context = BranchContext(self.repo_root, self._get_branch_config())
|
|
@@ -2059,8 +2108,8 @@ exit 0
|
|
|
2059
2108
|
else:
|
|
2060
2109
|
# For branches not in worktrees, we can update them directly
|
|
2061
2110
|
self.run_git(["checkout", branch], cwd=self.repo_root)
|
|
2062
|
-
self.run_git(
|
|
2063
|
-
["reset", "--hard", private_branch], cwd=self.repo_root
|
|
2111
|
+
self.run_git( # the branch, never a folder of the same name (0.9.12)
|
|
2112
|
+
["reset", "--hard", f"refs/heads/{private_branch}"], cwd=self.repo_root
|
|
2064
2113
|
)
|
|
2065
2114
|
self.logger.info(
|
|
2066
2115
|
f"Updated branch '{branch}' from {private_branch}"
|
|
@@ -2366,12 +2415,14 @@ exit 0
|
|
|
2366
2415
|
|
|
2367
2416
|
def _cleanup_sensitive_files(self, branch_context: Optional[str] = None, dry_run: bool = False) -> Dict[str, List[str]]:
|
|
2368
2417
|
"""
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2418
|
+
Take sensitive files out of a branch's git index, leaving them on disk.
|
|
2419
|
+
|
|
2420
|
+
Called while a public branch is cut. It removes tracked files matching
|
|
2421
|
+
the sensitive patterns from the index (`git rm --cached`) and never
|
|
2422
|
+
deletes anything from the working folder, which in the private-branch
|
|
2423
|
+
model is the private checkout (0.9.12). The 'working_dir' list in the
|
|
2424
|
+
result is always empty; it is kept for callers that read it.
|
|
2425
|
+
|
|
2375
2426
|
Args:
|
|
2376
2427
|
branch_context: Branch we're cleaning for (e.g. 'private', 'dev', 'main')
|
|
2377
2428
|
dry_run: If True, only report what would be cleaned
|
|
@@ -2411,65 +2462,18 @@ exit 0
|
|
|
2411
2462
|
cleanup_logger.info(f"Is private branch: {is_private_branch}")
|
|
2412
2463
|
cleanup_logger.info(f"Using {len(patterns_to_clean)} sensitive patterns: {patterns_to_clean}")
|
|
2413
2464
|
|
|
2414
|
-
#
|
|
2415
|
-
#
|
|
2416
|
-
|
|
2465
|
+
# The working folder is never cleaned, for any branch (0.9.12). In the
|
|
2466
|
+
# private-branch model a public branch is cut inside repo_root, which is
|
|
2467
|
+
# the PRIVATE checkout (<name>/local), so deleting matching files from
|
|
2468
|
+
# disk removed a person's untracked .env, logs and backups from their
|
|
2469
|
+
# own working folder. It never ran before 0.9.12 only because the reset
|
|
2470
|
+
# before it always failed. Taking files out of the public branch is the
|
|
2471
|
+
# index clean below, which leaves them on disk.
|
|
2472
|
+
clean_working_dir = False
|
|
2417
2473
|
clean_git_index = True # Always clean git index
|
|
2418
|
-
|
|
2419
|
-
cleanup_logger.info(f"Will clean working directory: {clean_working_dir}")
|
|
2420
|
-
cleanup_logger.info(f"Will clean git index: {clean_git_index}")
|
|
2421
|
-
|
|
2422
|
-
# Clean working directory files (only for public branches)
|
|
2423
|
-
if clean_working_dir:
|
|
2424
|
-
cleanup_logger.debug("Scanning working directory for sensitive files")
|
|
2425
|
-
for root, dirs, files in os.walk(self.repo_root):
|
|
2426
|
-
# Skip .git directory
|
|
2427
|
-
if ".git" in root.split(os.sep):
|
|
2428
|
-
continue
|
|
2429
|
-
|
|
2430
|
-
for file in files:
|
|
2431
|
-
file_path = os.path.join(root, file)
|
|
2432
|
-
relative_path = os.path.relpath(file_path, self.repo_root)
|
|
2433
|
-
if self._is_vendored(relative_path):
|
|
2434
|
-
continue
|
|
2435
2474
|
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
matching_pattern = None
|
|
2439
|
-
|
|
2440
|
-
for pattern in patterns_to_clean:
|
|
2441
|
-
# Cross-platform pattern matching using normalized paths
|
|
2442
|
-
normalized_relative = str(Path(relative_path)).replace('\\', '/')
|
|
2443
|
-
normalized_pattern = pattern.replace('\\', '/')
|
|
2444
|
-
|
|
2445
|
-
# Check multiple match approaches for cross-platform compatibility
|
|
2446
|
-
matches = [
|
|
2447
|
-
fnmatch.fnmatch(normalized_relative, normalized_pattern), # Full path
|
|
2448
|
-
fnmatch.fnmatch(file, normalized_pattern), # Filename only
|
|
2449
|
-
fnmatch.fnmatch(str(Path(file)), normalized_pattern), # Filename as Path
|
|
2450
|
-
]
|
|
2451
|
-
|
|
2452
|
-
if any(matches):
|
|
2453
|
-
should_remove = True
|
|
2454
|
-
matching_pattern = pattern
|
|
2455
|
-
if self.verbose >= 3:
|
|
2456
|
-
cleanup_logger.debug(f"Pattern '{pattern}' matched file '{relative_path}' (normalized: '{normalized_relative}')")
|
|
2457
|
-
break
|
|
2458
|
-
|
|
2459
|
-
if should_remove:
|
|
2460
|
-
cleanup_results["working_dir"].append(relative_path)
|
|
2461
|
-
|
|
2462
|
-
if dry_run:
|
|
2463
|
-
cleanup_logger.info(f"Would remove (working dir): {relative_path} (pattern: {matching_pattern})")
|
|
2464
|
-
else:
|
|
2465
|
-
try:
|
|
2466
|
-
os.remove(file_path)
|
|
2467
|
-
cleanup_logger.debug(f"Removed (working dir): {relative_path} (pattern: {matching_pattern})")
|
|
2468
|
-
except Exception as e:
|
|
2469
|
-
cleanup_logger.warning(f"Failed to remove {relative_path}: {str(e)}")
|
|
2470
|
-
else:
|
|
2471
|
-
cleanup_logger.info("Skipping working directory cleanup (private branch - files preserved)")
|
|
2472
|
-
|
|
2475
|
+
cleanup_logger.info(f"Will clean git index: {clean_git_index} (the working folder is never touched)")
|
|
2476
|
+
|
|
2473
2477
|
# Clean git index files (always done)
|
|
2474
2478
|
if clean_git_index:
|
|
2475
2479
|
cleanup_logger.debug("Scanning git index for sensitive files")
|
|
@@ -23,7 +23,7 @@ esac
|
|
|
23
23
|
|
|
24
24
|
# Check for private content using BranchContext patterns
|
|
25
25
|
has_private_content=0
|
|
26
|
-
for file in $(git diff --cached --name-only); do
|
|
26
|
+
for file in $(git diff --cached --name-only --diff-filter=ACMR); do
|
|
27
27
|
# Check against all private content patterns from BranchContext
|
|
28
28
|
if echo "$file" | grep -q -E "$private_content_regex"; then
|
|
29
29
|
if [ $has_private_content -eq 0 ]; then
|
|
@@ -50,7 +50,7 @@ if [ $has_private_content -eq 1 ]; then
|
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
52
|
# Check for large files (>10MB)
|
|
53
|
-
for file in $(git diff --cached --name-only); do
|
|
53
|
+
for file in $(git diff --cached --name-only --diff-filter=ACMR); do
|
|
54
54
|
if [ -f "$file" ]; then
|
|
55
55
|
size=$(du -k "$file" | awk '{print $1}')
|
|
56
56
|
if [ "$size" -gt 10240 ]; then
|
|
@@ -504,7 +504,7 @@ def test_write_settings_merges_missing_keys_and_never_overwrites(tmp_path):
|
|
|
504
504
|
assert common_kit.write_settings(str(tmp_path), {"private-patterns": ["CLAUDE.md"], "languages": ["NOT-THIS"]}) == ".repokit-common.toml"
|
|
505
505
|
assert f.read_bytes() == (b'[tool.repokit-common]\r\nprivate-patterns = ["CLAUDE.md"]\r\n'
|
|
506
506
|
b'version-source = "include/x/version.h"\r\nlanguages = ["c-cpp"]\r\n')
|
|
507
|
-
assert common_kit.write_settings(str(tmp_path), {"
|
|
507
|
+
assert common_kit.write_settings(str(tmp_path), {"languages": ["other"]}) is None # present: untouched
|
|
508
508
|
py = tmp_path / "pyproject.toml"
|
|
509
509
|
py.write_text('[project]\nname = "p"\n\n[tool.repokit-common]\nversion-source = "p/_version.py"\n\n[tool.other]\nx = 1\n')
|
|
510
510
|
assert common_kit.write_settings(str(tmp_path), {"private-branches": ["private", "scratch"]}) == "pyproject.toml"
|
|
@@ -512,6 +512,44 @@ def test_write_settings_merges_missing_keys_and_never_overwrites(tmp_path):
|
|
|
512
512
|
'version-source = "p/_version.py"\n\n[tool.other]\nx = 1\n')
|
|
513
513
|
|
|
514
514
|
|
|
515
|
+
def test_write_settings_adds_the_private_patterns_an_existing_list_lacks(tmp_path):
|
|
516
|
+
"""0.9.12: a table that already has private-patterns (the pypi layer's
|
|
517
|
+
pyproject.toml ships one) keeps its entries and gains the ones the
|
|
518
|
+
private-branch model needs -- skipping the key dropped CLAUDE.md from
|
|
519
|
+
the guard on public branches. Other keys are still never overwritten."""
|
|
520
|
+
py = tmp_path / "pyproject.toml"
|
|
521
|
+
py.write_text('[tool.repokit-common]\nversion-source = "p/_version.py"\n'
|
|
522
|
+
'private-patterns = ["private/", "local/", ".env"]\n\n[tool.other]\nx = ["CLAUDE.md"]\n')
|
|
523
|
+
settings = {"private-patterns": ["CLAUDE.md", "private/", "convos/"], "version-source": ["NOT-THIS"]}
|
|
524
|
+
assert common_kit.write_settings(str(tmp_path), settings) == "pyproject.toml"
|
|
525
|
+
assert py.read_text() == ('[tool.repokit-common]\nversion-source = "p/_version.py"\n'
|
|
526
|
+
'private-patterns = ["private/", "local/", ".env", "CLAUDE.md", "convos/"]\n\n'
|
|
527
|
+
'[tool.other]\nx = ["CLAUDE.md"]\n')
|
|
528
|
+
assert common_kit.write_settings(str(tmp_path), settings) is None # nothing missing any more
|
|
529
|
+
|
|
530
|
+
toml = tmp_path / "sub"
|
|
531
|
+
toml.mkdir()
|
|
532
|
+
f = toml / ".repokit-common.toml"
|
|
533
|
+
f.write_bytes(b"[tool.repokit-common]\r\nprivate-patterns = [\r\n 'private/',\r\n]\r\n")
|
|
534
|
+
assert common_kit.write_settings(str(toml), {"private-patterns": ["CLAUDE.md"]}) == ".repokit-common.toml"
|
|
535
|
+
assert f.read_bytes() == b"[tool.repokit-common]\r\nprivate-patterns = [\r\n 'private/', \"CLAUDE.md\"\r\n]\r\n"
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def test_write_settings_union_stays_in_its_own_list_and_table(tmp_path):
|
|
539
|
+
"""0.9.12: the union reads single-quoted entries as present, adds only to
|
|
540
|
+
the private-patterns list (not to a list after it), and the table ends at
|
|
541
|
+
the next header -- a key of the same name in a later table neither counts
|
|
542
|
+
as present nor receives anything. Found by the 0.9.12 mutation sweep."""
|
|
543
|
+
py = tmp_path / "pyproject.toml"
|
|
544
|
+
py.write_text("[tool.repokit-common]\nprivate-patterns = ['private/', \"local/\"]\nlanguages = [\"python\"]\n\n"
|
|
545
|
+
"[tool.other]\nprivate-branches = [\"x\"]\n")
|
|
546
|
+
settings = {"private-patterns": ["private/", "CLAUDE.md"], "private-branches": ["private", "scratch"]}
|
|
547
|
+
assert common_kit.write_settings(str(tmp_path), settings) == "pyproject.toml"
|
|
548
|
+
assert py.read_text() == ("[tool.repokit-common]\nprivate-branches = [\"private\", \"scratch\"]\n"
|
|
549
|
+
"private-patterns = ['private/', \"local/\", \"CLAUDE.md\"]\nlanguages = [\"python\"]\n\n"
|
|
550
|
+
"[tool.other]\nprivate-branches = [\"x\"]\n")
|
|
551
|
+
|
|
552
|
+
|
|
515
553
|
# --- U2.3: packaging ----------------------------------------------------------
|
|
516
554
|
|
|
517
555
|
@pytest.mark.integration
|
|
@@ -114,6 +114,17 @@ class TestPrivateBranchModelWithCommon(RepoKitTestCase):
|
|
|
114
114
|
allowed = commit_file(local, "CLAUDE.md")
|
|
115
115
|
self.assertEqual(allowed.returncode, 0, allowed.stdout + allowed.stderr)
|
|
116
116
|
|
|
117
|
+
def test_claude_md_refused_on_main_of_a_python_project(self):
|
|
118
|
+
"""0.9.12: a Python project's pyproject.toml ships its own private-patterns;
|
|
119
|
+
the private-branch entries must be added to that list, or CLAUDE.md
|
|
120
|
+
reaches main (committed from the github worktree)."""
|
|
121
|
+
self.assert_repokit_success(["create", "demo", "--branch-strategy", "simple", "--with-common",
|
|
122
|
+
"--language", "python", "--no-push"])
|
|
123
|
+
github = os.path.join(self.test_dir, "demo", "github")
|
|
124
|
+
self.assertIn('"CLAUDE.md"', Path(github, "pyproject.toml").read_text(encoding="utf-8"))
|
|
125
|
+
refused = commit_file(github, "CLAUDE.md")
|
|
126
|
+
self.assertNotEqual(refused.returncode, 0, refused.stdout + refused.stderr)
|
|
127
|
+
|
|
117
128
|
def test_a_custom_private_branch_is_written_to_the_settings(self):
|
|
118
129
|
self.assert_repokit_success(["create", "demo", "--branch-strategy", "simple",
|
|
119
130
|
"--private-branch", "scratch", "--with-common", "--no-push"])
|