opengate-gate-tree 0.1.1__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.
Files changed (41) hide show
  1. opengate_gate_tree-0.1.1/.github/PULL_REQUEST_TEMPLATE.md +27 -0
  2. opengate_gate_tree-0.1.1/.github/copilot-instructions.md +78 -0
  3. opengate_gate_tree-0.1.1/.github/get_review.sh +119 -0
  4. opengate_gate_tree-0.1.1/.github/workflows/ci.yaml +48 -0
  5. opengate_gate_tree-0.1.1/.github/workflows/publish.yml +32 -0
  6. opengate_gate_tree-0.1.1/.gitignore +18 -0
  7. opengate_gate_tree-0.1.1/.pre-commit-config.yaml +10 -0
  8. opengate_gate_tree-0.1.1/CLAUDE.md +99 -0
  9. opengate_gate_tree-0.1.1/LICENSE +23 -0
  10. opengate_gate_tree-0.1.1/Makefile +108 -0
  11. opengate_gate_tree-0.1.1/PKG-INFO +180 -0
  12. opengate_gate_tree-0.1.1/README.md +160 -0
  13. opengate_gate_tree-0.1.1/docs/CODING_CONVENTIONS.md +498 -0
  14. opengate_gate_tree-0.1.1/docs/COMMIT_CONVENTIONS.md +79 -0
  15. opengate_gate_tree-0.1.1/docs/CONTRIBUTION.md +100 -0
  16. opengate_gate_tree-0.1.1/docs/ROADMAP.md +260 -0
  17. opengate_gate_tree-0.1.1/docs/TESTING_CONVENTIONS.md +487 -0
  18. opengate_gate_tree-0.1.1/docs/VERSION_UPGRADE_CONVENTIONS.md +155 -0
  19. opengate_gate_tree-0.1.1/pyproject.toml +75 -0
  20. opengate_gate_tree-0.1.1/scripts/update_version_in_files.sh +101 -0
  21. opengate_gate_tree-0.1.1/src/opengate_gate_tree/__init__.py +13 -0
  22. opengate_gate_tree-0.1.1/src/opengate_gate_tree/__main__.py +11 -0
  23. opengate_gate_tree-0.1.1/src/opengate_gate_tree/cli.py +200 -0
  24. opengate_gate_tree-0.1.1/src/opengate_gate_tree/config.py +44 -0
  25. opengate_gate_tree-0.1.1/src/opengate_gate_tree/io/fileformat.py +39 -0
  26. opengate_gate_tree-0.1.1/src/opengate_gate_tree/logger.py +10 -0
  27. opengate_gate_tree-0.1.1/src/opengate_gate_tree/logging_setup.py +56 -0
  28. opengate_gate_tree-0.1.1/src/opengate_gate_tree/tree/branch.py +35 -0
  29. opengate_gate_tree-0.1.1/src/opengate_gate_tree/tree/gatetree.py +37 -0
  30. opengate_gate_tree-0.1.1/tests/fixtures/.gitkeep +0 -0
  31. opengate_gate_tree-0.1.1/tests/integration/.gitkeep +0 -0
  32. opengate_gate_tree-0.1.1/tests/smoke/test_version.py +55 -0
  33. opengate_gate_tree-0.1.1/tests/unit/.gitkeep +0 -0
  34. opengate_gate_tree-0.1.1/tests/unit/test_branch.py +22 -0
  35. opengate_gate_tree-0.1.1/tests/unit/test_cli.py +112 -0
  36. opengate_gate_tree-0.1.1/tests/unit/test_config.py +36 -0
  37. opengate_gate_tree-0.1.1/tests/unit/test_fileformat.py +18 -0
  38. opengate_gate_tree-0.1.1/tests/unit/test_gatetree.py +18 -0
  39. opengate_gate_tree-0.1.1/tests/unit/test_logger.py +18 -0
  40. opengate_gate_tree-0.1.1/tests/unit/test_logging_setup.py +33 -0
  41. opengate_gate_tree-0.1.1/tests/unit/test_main_entrypoint.py +29 -0
@@ -0,0 +1,27 @@
1
+ ## Description
2
+ Brief description of what this PR does.
3
+
4
+ ## Related Issues
5
+ Closes #123
6
+ Related to #456
7
+
8
+ ## Changes
9
+ - Change 1
10
+ - Change 2
11
+ - Change 3
12
+
13
+ ## Type of Change
14
+ - [ ] Bug fix (non-breaking)
15
+ - [ ] New feature (non-breaking)
16
+ - [ ] Breaking change
17
+ - [ ] Documentation update
18
+
19
+ ## Testing
20
+ Describe tests added or how changes were tested.
21
+
22
+ ## Checklist
23
+ - [ ] Code follows style guidelines
24
+ - [ ] Tests added and passing
25
+ - [ ] Documentation updated
26
+ - [ ] Commit messages are clear
27
+ - [ ] No merge conflicts
@@ -0,0 +1,78 @@
1
+ # Copilot Instructions
2
+
3
+ These instructions apply to all changes in this repository.
4
+
5
+ ## Project Context
6
+
7
+ - Package name: `opengate-gate-tree`
8
+ - Source root: `src/opengate_gate_tree`
9
+ - Supported Python versions: 3.11-3.14
10
+ - Environment and dependency manager: `uv`
11
+
12
+ ## Development Workflow
13
+
14
+ - Prefer Make targets for common tasks:
15
+ - `make init`
16
+ - `make lint`
17
+ - `make format`
18
+ - `make typecheck`
19
+ - `make test`
20
+ - `make check`
21
+ - Keep changes focused and minimal.
22
+ - Do not introduce unrelated refactors in the same change.
23
+
24
+ ## Repository Standards
25
+
26
+ - Follow coding conventions from [../docs/CODING_CONVENTIONS.md](../docs/CODING_CONVENTIONS.md).
27
+ - Follow testing conventions from [../docs/TESTING_CONVENTIONS.md](../docs/TESTING_CONVENTIONS.md).
28
+
29
+ ## Code Quality Requirements
30
+
31
+ - Keep code and user-facing messages in English.
32
+ - Follow type hints consistently; this repository uses strict mypy settings.
33
+ - Keep line length within Ruff limits (100 characters).
34
+ - Preserve existing module structure and naming conventions.
35
+ - Treat [../docs/CODING_CONVENTIONS.md](../docs/CODING_CONVENTIONS.md) as authoritative for style decisions.
36
+
37
+ ## Testing Requirements
38
+
39
+ - Add or update tests when behavior changes.
40
+ - Place unit tests under `tests/unit`.
41
+ - Ensure tests target current modules from `opengate_gate_tree` (not legacy project names).
42
+ - Avoid adding test dependencies that are not declared in `pyproject.toml`.
43
+ - Treat [../docs/TESTING_CONVENTIONS.md](../docs/TESTING_CONVENTIONS.md) as authoritative for test structure.
44
+
45
+ ## Validation Before Finishing
46
+
47
+ Run full validation before finalizing code changes:
48
+
49
+ ```bash
50
+ make check
51
+ ```
52
+
53
+ If pre-commit is enabled, ensure hooks pass:
54
+
55
+ ```bash
56
+ uv run pre-commit run --all-files
57
+ ```
58
+
59
+ ## Versioning and Release Rules
60
+
61
+ - For version bumps, use:
62
+
63
+ ```bash
64
+ bash script/update_version_in_files.sh "$VERSION"
65
+ ```
66
+
67
+ - Follow the release procedure in `docs/VERSION_UPGRADE_CONVENTIONS.md`.
68
+ - Release publication is allowed only on `main` and only by repository admins.
69
+
70
+ ## Commit and PR Hygiene
71
+
72
+ - Follow commit format rules from `docs/COMMIT_CONVENTIONS.md`.
73
+ - Keep commit messages explicit and scoped.
74
+ - Ensure PR descriptions use `.github/PULL_REQUEST_TEMPLATE.md`.
75
+
76
+ ## Agent configuration
77
+
78
+ Additional generalised settings for agents are in a directory `.agents`
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ if ! command -v gh >/dev/null 2>&1; then
6
+ echo "Error: required tool 'gh' is not installed." >&2
7
+ exit 1
8
+ fi
9
+
10
+ if ! command -v jq >/dev/null 2>&1; then
11
+ echo "Error: required tool 'jq' is not installed." >&2
12
+ exit 1
13
+ fi
14
+
15
+ if ! gh auth status >/dev/null 2>&1; then
16
+ echo "Error: you are not signed in to gh. Run: gh auth login" >&2
17
+ exit 1
18
+ fi
19
+
20
+ BRANCH="$(git rev-parse --abbrev-ref HEAD)"
21
+ REPO_FULL="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
22
+ OWNER="${REPO_FULL%/*}"
23
+ REPO="${REPO_FULL#*/}"
24
+
25
+ OUTPUT_DIR=".tmp/code-reviews"
26
+ mkdir -p "$OUTPUT_DIR"
27
+
28
+ BRANCH_SAFE="$(echo "$BRANCH" | sed -E 's/[^A-Za-z0-9._-]+/-/g')"
29
+ if [[ -z "$BRANCH_SAFE" ]]; then
30
+ BRANCH_SAFE="unknown-branch"
31
+ fi
32
+
33
+ FETCH_DATE="$(date '+%Y%m%d-%H%M%S')"
34
+ FETCH_DAY="${FETCH_DATE%%-*}"
35
+ EXISTING_COUNT="$({
36
+ find "$OUTPUT_DIR" -maxdepth 1 -type f \
37
+ -name "pr-code-review-${BRANCH_SAFE}-${FETCH_DAY}-*.md"
38
+ } | wc -l | tr -d '[:space:]')"
39
+ ORDER_NUMBER="$(printf '%02d' "$((EXISTING_COUNT + 1))")"
40
+ OUTPUT_FILE="${OUTPUT_DIR}/pr-code-review-${BRANCH_SAFE}-${FETCH_DATE}-${ORDER_NUMBER}.md"
41
+
42
+ PRS_JSON="$(gh pr list --state open --head "$BRANCH" --json number,title,url,headRefName,author 2>/dev/null || true)"
43
+
44
+ if [[ -z "$PRS_JSON" || "$PRS_JSON" == "[]" ]]; then
45
+ {
46
+ echo "# Review tasks"
47
+ echo
48
+ echo "No open PR found for branch: $BRANCH."
49
+ } >"$OUTPUT_FILE"
50
+ echo "Saved: $OUTPUT_FILE"
51
+ exit 0
52
+ fi
53
+
54
+ PR_NUMBERS="$(echo "$PRS_JSON" | jq -r '.[].number')"
55
+ FIRST_PR_NUMBER="$(echo "$PR_NUMBERS" | head -n1)"
56
+
57
+ GRAPHQL_QUERY='query($owner:String!, $repo:String!, $number:Int!) {
58
+ repository(owner:$owner, name:$repo) {
59
+ pullRequest(number:$number) {
60
+ number
61
+ title
62
+ url
63
+ headRefName
64
+ reviewThreads(first: 100) {
65
+ nodes {
66
+ isResolved
67
+ isOutdated
68
+ path
69
+ line
70
+ startLine
71
+ comments(first: 100) {
72
+ nodes {
73
+ author { login }
74
+ body
75
+ url
76
+ createdAt
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }'
84
+
85
+ PR_JSON="$(gh api graphql -f query="$GRAPHQL_QUERY" -F owner="$OWNER" -F repo="$REPO" -F number="$FIRST_PR_NUMBER")"
86
+
87
+ UNRESOLVED_COUNT="$(echo "$PR_JSON" | jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length')"
88
+
89
+ {
90
+ echo "# Review tasks"
91
+ echo
92
+ echo "Repository: \`$REPO_FULL\` "
93
+ echo "Branch: \`$BRANCH\` "
94
+ echo "PR: [#${FIRST_PR_NUMBER}]($(echo "$PR_JSON" | jq -r '.data.repository.pullRequest.url')) - $(echo "$PR_JSON" | jq -r '.data.repository.pullRequest.title')"
95
+ echo
96
+ echo "## Unresolved threads"
97
+ echo
98
+
99
+ if [[ "$UNRESOLVED_COUNT" -eq 0 ]]; then
100
+ echo "No unresolved threads ✅"
101
+ else
102
+ echo "$PR_JSON" | jq -r '
103
+ .data.repository.pullRequest.reviewThreads.nodes
104
+ | map(select(.isResolved == false))
105
+ | to_entries[]
106
+ | .value as $t
107
+ | $t.comments.nodes[0] as $c
108
+ | "- [ ] "
109
+ + "[" + ($t.path // "(brak pliku)")
110
+ + (if ($t.line // $t.startLine) then ":L" + (($t.line // $t.startLine)|tostring) else "" end)
111
+ + "](" + ($c.url // "") + ")"
112
+ + " — @" + ($c.author.login // "unknown")
113
+ + (if $t.isOutdated then " *(outdated)*" else "" end)
114
+ + "\n > " + (($c.body // "") | gsub("\n"; " ") | gsub("\r"; " ") | .[0:50000])
115
+ '
116
+ fi
117
+ } >"$OUTPUT_FILE"
118
+
119
+ echo "Saved: $OUTPUT_FILE"
@@ -0,0 +1,48 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - develop
8
+ pull_request:
9
+ branches:
10
+ - main
11
+ - develop
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ concurrency:
18
+ group: ci-${{ github.workflow }}-${{ github.ref }}
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ check:
23
+ name: check (Python ${{ matrix.python-version }})
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
29
+
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@v4
33
+
34
+ - name: Set up Python
35
+ uses: actions/setup-python@v5
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+
39
+ - name: Set up uv
40
+ uses: astral-sh/setup-uv@v5
41
+ with:
42
+ enable-cache: true
43
+
44
+ - name: Install dependencies
45
+ run: make init
46
+
47
+ - name: Run full validation
48
+ run: make check
@@ -0,0 +1,32 @@
1
+ name: publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - name: Install uv
13
+ uses: astral-sh/setup-uv@v5
14
+ - name: Build sdist and wheel
15
+ run: uv build
16
+ - uses: actions/upload-artifact@v4
17
+ with:
18
+ name: dist
19
+ path: dist/
20
+
21
+ publish:
22
+ needs: build
23
+ runs-on: ubuntu-latest
24
+ environment: pypi
25
+ permissions:
26
+ id-token: write
27
+ steps:
28
+ - uses: actions/download-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ .coverage
8
+ .coverage.*
9
+ htmlcov/
10
+ .venv/
11
+ venv/
12
+ .env
13
+ .tmp/
14
+ examples/output/
15
+ uv.lock
16
+ .claude/
17
+ worktrees/
18
+ .agents/
@@ -0,0 +1,10 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: make-check
5
+ name: Run make check
6
+ entry: make check
7
+ language: system
8
+ pass_filenames: false
9
+ always_run: true
10
+ stages: [pre-commit]
@@ -0,0 +1,99 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides project-level instructions for Claude Code.
4
+
5
+ ## Scope and priorities
6
+
7
+ - Apply these rules to all work in this repository.
8
+ - Keep instructions specific, verifiable, and concise.
9
+ - Prefer project conventions over generic defaults.
10
+
11
+ ## Project snapshot
12
+
13
+ - Package: opengate-gate-tree
14
+ - Source root: src/opengate_gate_tree
15
+ - Tests root: tests/unit
16
+ - Python support: 3.11-3.14
17
+ - Tooling: uv, ruff, mypy, pytest, pre-commit
18
+
19
+ ## Required workflow
20
+
21
+ Use repository Make targets when available:
22
+
23
+ ```bash
24
+ make init
25
+ make lint
26
+ make format
27
+ make typecheck
28
+ make test
29
+ make check
30
+ ```
31
+
32
+ If CLI tools are needed, run them via uv in this repository:
33
+
34
+ ```bash
35
+ uv run <tool>
36
+ ```
37
+
38
+ ## Non-negotiable checks before finishing changes
39
+
40
+ Run:
41
+
42
+ ```bash
43
+ make check
44
+ ```
45
+
46
+ If pre-commit is enabled, also run:
47
+
48
+ ```bash
49
+ uv run pre-commit run --all-files
50
+ ```
51
+
52
+ Do not consider work complete while these checks fail.
53
+
54
+ ## Coding rules
55
+
56
+ - Keep code, comments, docs, and user-facing messages in English.
57
+ - Keep edits minimal and focused; avoid unrelated refactors.
58
+ - Follow strict type hints; this project uses strict mypy settings.
59
+ - Keep line length within Ruff limits (100).
60
+ - Preserve current package/module naming and folder layout.
61
+
62
+ Authoritative coding standard:
63
+ - docs/CODING_CONVENTIONS.md
64
+
65
+ ## Testing rules
66
+
67
+ - Add or update tests when behavior changes.
68
+ - Keep unit tests under tests/unit.
69
+ - Target current modules from opengate_gate_macro_fold.
70
+ - Do not reintroduce legacy imports or names from other projects.
71
+
72
+ Authoritative testing standard:
73
+ - docs/TESTING_CONVENTIONS.md
74
+
75
+ ## Versioning and release
76
+
77
+ - Version releases are allowed only on main and only by admins.
78
+ - For version updates in files, use:
79
+
80
+ ```bash
81
+ bash script/update_version_in_files.sh "$VERSION"
82
+ ```
83
+
84
+ Authoritative release process:
85
+ - docs/VERSION_UPGRADE_CONVENTIONS.md
86
+
87
+ ## Commit and PR hygiene
88
+
89
+ - Follow docs/COMMIT_CONVENTIONS.md for commit message format.
90
+ - Use .github/PULL_REQUEST_TEMPLATE.md for PR descriptions.
91
+
92
+ ## Repository-specific pitfalls to avoid
93
+
94
+ - Do not add obsolete console script aliases from older projects.
95
+ - Ensure tests and docs match the current package name and module paths.
96
+
97
+ ## Agent configuration
98
+
99
+ Additional generalised settings for agents are in a directory `.agents`
@@ -0,0 +1,23 @@
1
+ # MIT License
2
+
3
+ **Project:** opengate-gate-tree
4
+
5
+ Copyright (c) 2026 Mateusz Jakub Bała
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # FILE: Makefile
2
+ # ABOUT: Project helper tasks: installation, validation, and worktree
3
+ # management for feature branches created from develop.
4
+ # USAGE:
5
+ # make init | install | install-user | test | lint | format | typecheck | check
6
+ # make worktree BRANCH_NAME=feature/description
7
+ # make switch-to-worktree BRANCH_NAME=feature/description
8
+
9
+ SHELL := /bin/bash
10
+
11
+ # Parent directory for worktrees and directory for lock files.
12
+ WORKTREE_ROOT ?= ./worktrees
13
+ WORKTREE_LOCKS_DIR ?= .tmp/worktree-locks
14
+
15
+ .PHONY: init install install-user test lint format typecheck check worktree switch-to-worktree
16
+
17
+ # Install dependencies and create the virtual environment (uv).
18
+ init:
19
+ uv sync
20
+
21
+ # Install project dependencies and package into the local .venv.
22
+ install: init
23
+ @echo "Installed in local virtual environment: .venv"
24
+ @echo "Run via uv: uv run opengate-gate-tree --help"
25
+ @echo "Or activate the environment: source .venv/bin/activate"
26
+
27
+ # Install the package for the current user (outside project .venv).
28
+ install-user:
29
+ python3 -m pip install --user -e .
30
+ @echo "Installed in user site-packages (--user)."
31
+ @echo "If needed, add ~/.local/bin to PATH."
32
+
33
+ # Run the full test suite.
34
+ test:
35
+ uv run pytest
36
+
37
+ # Check code style (lint).
38
+ lint:
39
+ uv run ruff check
40
+
41
+ # Format code.
42
+ format:
43
+ uv run ruff format
44
+
45
+ # Static type checking.
46
+ typecheck:
47
+ uv run mypy src/
48
+
49
+ # Full local validation: lint, formatting check, types, tests.
50
+ check:
51
+ uv run ruff check
52
+ uv run ruff format --check
53
+ uv run mypy src/
54
+ uv run pytest
55
+
56
+ # Create a worktree for the given branch if it does not already exist.
57
+ worktree:
58
+ @if [[ -z "$(BRANCH_NAME)" ]]; then \
59
+ echo "Error: set BRANCH_NAME, e.g. make worktree BRANCH_NAME=worktree/branch/name." >&2; \
60
+ exit 1; \
61
+ fi
62
+ @WORKTREE_DIR="$(WORKTREE_ROOT)/$$(echo "$(BRANCH_NAME)" | tr '/' '-')"; \
63
+ mkdir -p "$(WORKTREE_ROOT)"; \
64
+ if git worktree list --porcelain | grep -Fxq "branch refs/heads/$(BRANCH_NAME)"; then \
65
+ echo "Worktree for branch $(BRANCH_NAME) already exists."; \
66
+ exit 0; \
67
+ fi; \
68
+ if git show-ref --verify --quiet "refs/heads/$(BRANCH_NAME)"; then \
69
+ git worktree add "$$WORKTREE_DIR" "$(BRANCH_NAME)"; \
70
+ else \
71
+ git worktree add -b "$(BRANCH_NAME)" "$$WORKTREE_DIR" develop; \
72
+ fi; \
73
+ echo "Created worktree: $$WORKTREE_DIR (branch: $(BRANCH_NAME))."
74
+
75
+ # Switch to an existing worktree if it is not locked by another instance.
76
+ switch-to-worktree:
77
+ @if [[ -z "$(BRANCH_NAME)" ]]; then \
78
+ echo "Error: set BRANCH_NAME, e.g. make switch-to-worktree BRANCH_NAME=worktree/branch/name." >&2; \
79
+ exit 1; \
80
+ fi
81
+ @if ! git show-ref --verify --quiet "refs/heads/$(BRANCH_NAME)"; then \
82
+ echo "Error: the specified branch does not exist: $(BRANCH_NAME)." >&2; \
83
+ exit 1; \
84
+ fi
85
+ @WORKTREE_DIR="$$(git worktree list --porcelain | awk -v target="refs/heads/$(BRANCH_NAME)" '\
86
+ $$1=="worktree" { path=$$2 } \
87
+ $$1=="branch" && $$2==target { print path; exit }')"; \
88
+ if [[ -z "$$WORKTREE_DIR" ]]; then \
89
+ echo "Error: no worktree exists for branch $(BRANCH_NAME). First run make worktree BRANCH_NAME=$(BRANCH_NAME)." >&2; \
90
+ exit 1; \
91
+ fi; \
92
+ LOCK_FILE="$(WORKTREE_LOCKS_DIR)/$$(echo "$(BRANCH_NAME)" | tr '/' '-').lock"; \
93
+ mkdir -p "$(WORKTREE_LOCKS_DIR)"; \
94
+ if [[ -f "$$LOCK_FILE" ]]; then \
95
+ LOCK_PID="$$(cat "$$LOCK_FILE")"; \
96
+ if [[ -n "$$LOCK_PID" ]] && kill -0 "$$LOCK_PID" 2>/dev/null; then \
97
+ echo "Error: the worktree is already locked by another instance (PID: $$LOCK_PID)." >&2; \
98
+ echo "How to release it: stop the process with PID $$LOCK_PID (for example, close the shell holding the lock)." >&2; \
99
+ exit 1; \
100
+ fi; \
101
+ rm -f "$$LOCK_FILE"; \
102
+ fi; \
103
+ echo "$$BASHPID" > "$$LOCK_FILE"; \
104
+ cleanup() { rm -f "$$LOCK_FILE"; }; \
105
+ trap cleanup EXIT INT TERM; \
106
+ echo "Switched to $$WORKTREE_DIR. To release the lock, close this shell."; \
107
+ cd "$$WORKTREE_DIR"; \
108
+ "$${SHELL:-/bin/bash}" -i