codigest 0.4.1__tar.gz → 0.4.3__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.
- codigest-0.4.3/.github/workflows/publish.yml +51 -0
- codigest-0.4.3/.github/workflows/tests.yml +15 -0
- {codigest-0.4.1 → codigest-0.4.3}/CITATION.cff +1 -1
- {codigest-0.4.1 → codigest-0.4.3}/PKG-INFO +11 -3
- {codigest-0.4.1 → codigest-0.4.3}/README.md +10 -2
- {codigest-0.4.1 → codigest-0.4.3}/pyproject.toml +1 -1
- codigest-0.4.3/server.json +28 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/mcp.py +11 -5
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/term.py +11 -3
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/termstore.py +15 -1
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/shell/hook.ps1 +1 -1
- {codigest-0.4.1 → codigest-0.4.3}/tests/test_termstore.py +14 -0
- {codigest-0.4.1 → codigest-0.4.3}/uv.lock +1 -1
- codigest-0.4.1/.github/workflows/publish.yml +0 -73
- {codigest-0.4.1 → codigest-0.4.3}/.gitignore +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/.python-version +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/LICENSE +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/__init__.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/__main__.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/cap.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/clean.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/diff.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/digest.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/init.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/scan.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/semdiff.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/status.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/commands/tree.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/config.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/cache.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/common.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/git_ops.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/output.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/processor.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/prompts.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/redact.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/resolver.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/runner.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/scanner.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/semdiff.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/shadow.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/shellhist.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/structure.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/tags.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/core/tokenizer.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/main.py +0 -0
- {codigest-0.4.1 → codigest-0.4.3}/src/codigest/options.py +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
pypi:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: release
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write # PyPI Trusted Publishing
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
19
|
+
- run: uv python install 3.15
|
|
20
|
+
- run: uv build
|
|
21
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
22
|
+
|
|
23
|
+
mcp:
|
|
24
|
+
name: Publish to the MCP registry
|
|
25
|
+
needs: pypi
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
id-token: write # GitHub OIDC login for io.github.NaNIsaac/*
|
|
29
|
+
contents: read
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v7
|
|
32
|
+
|
|
33
|
+
- name: Set server.json version from the tag
|
|
34
|
+
run: |
|
|
35
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
36
|
+
jq --arg v "$VERSION" '.version = $v | .packages[0].version = $v' server.json > server.tmp
|
|
37
|
+
mv server.tmp server.json
|
|
38
|
+
# The registry verifies the package on PyPI; wait until the release is visible.
|
|
39
|
+
for i in $(seq 30); do
|
|
40
|
+
curl -sf "https://pypi.org/pypi/codigest/$VERSION/json" > /dev/null && exit 0
|
|
41
|
+
sleep 10
|
|
42
|
+
done
|
|
43
|
+
echo "codigest $VERSION not visible on PyPI" && exit 1
|
|
44
|
+
|
|
45
|
+
- name: Install mcp-publisher
|
|
46
|
+
run: curl -sL https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz | tar xz mcp-publisher
|
|
47
|
+
|
|
48
|
+
- name: Publish
|
|
49
|
+
run: |
|
|
50
|
+
./mcp-publisher login github-oidc
|
|
51
|
+
./mcp-publisher publish
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v7
|
|
13
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
14
|
+
- run: uv python install 3.15
|
|
15
|
+
- run: uv run --with pytest pytest -q
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: codigest
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Human-Centered Codebase Context Manager for LLMs
|
|
5
5
|
Project-URL: Homepage, https://github.com/NaNIsaac/codigest
|
|
6
6
|
Project-URL: Repository, https://github.com/NaNIsaac/codigest
|
|
@@ -26,6 +26,12 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
|
|
27
27
|
# Codigest
|
|
28
28
|
|
|
29
|
+
[](https://pypi.org/project/codigest/)
|
|
30
|
+
[](https://pepy.tech/project/codigest)
|
|
31
|
+
[](https://github.com/NaNIsaac/codigest/actions/workflows/tests.yml)
|
|
32
|
+
|
|
33
|
+
<!-- mcp-name: io.github.NaNIsaac/codigest -->
|
|
34
|
+
|
|
29
35
|
**Codigest** is a standalone CLI tool designed to extract, structure, and track the context of your codebase for Large Language Models (LLMs).
|
|
30
36
|
|
|
31
37
|
Unlike simple copy-paste tools, Codigest employs a **Context Anchor** system (Shadow Git) to track changes locally without polluting your main version control history. It also features **Semantic Analysis** to detect structural changes in your code.
|
|
@@ -35,7 +41,8 @@ Unlike simple copy-paste tools, Codigest employs a **Context Anchor** system (Sh
|
|
|
35
41
|
## Quickstart
|
|
36
42
|
|
|
37
43
|
```bash
|
|
38
|
-
|
|
44
|
+
uvx codigest scan # try it without installing
|
|
45
|
+
uv tool install codigest # or install the `cdg` command
|
|
39
46
|
|
|
40
47
|
cdg scan # whole project as LLM-ready XML (copied to clipboard)
|
|
41
48
|
cdg init && cdg diff # set an anchor, later get only what changed
|
|
@@ -231,6 +238,7 @@ cdg term # last command
|
|
|
231
238
|
cdg term -n 3 # last 3 commands
|
|
232
239
|
cdg term -i 2 # only the command from 2 runs ago
|
|
233
240
|
cdg term -f # last failed command
|
|
241
|
+
cdg term --here -n 3 # last 3 commands run in this project
|
|
234
242
|
|
|
235
243
|
cdg term path # where captures are stored (override with CODIGEST_HOME)
|
|
236
244
|
cdg term clear # delete all captures
|
|
@@ -242,7 +250,7 @@ cdg term clear # delete all captures
|
|
|
242
250
|
|
|
243
251
|
| Tool | Returns |
|
|
244
252
|
| --- | --- |
|
|
245
|
-
| `terminal_history` | Recent commands with output and exit code (`count`, `failed`) |
|
|
253
|
+
| `terminal_history` | Recent commands with output and exit code (`count`, `failed`, `here`: only this project, default on) |
|
|
246
254
|
| `scan` | Project snapshot (`targets`, `resolve`, `message`) |
|
|
247
255
|
| `diff` / `semdiff` | Text / structural changes since the anchor |
|
|
248
256
|
| `digest` | Signatures and docstrings only |
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Codigest
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/codigest/)
|
|
4
|
+
[](https://pepy.tech/project/codigest)
|
|
5
|
+
[](https://github.com/NaNIsaac/codigest/actions/workflows/tests.yml)
|
|
6
|
+
|
|
7
|
+
<!-- mcp-name: io.github.NaNIsaac/codigest -->
|
|
8
|
+
|
|
3
9
|
**Codigest** is a standalone CLI tool designed to extract, structure, and track the context of your codebase for Large Language Models (LLMs).
|
|
4
10
|
|
|
5
11
|
Unlike simple copy-paste tools, Codigest employs a **Context Anchor** system (Shadow Git) to track changes locally without polluting your main version control history. It also features **Semantic Analysis** to detect structural changes in your code.
|
|
@@ -9,7 +15,8 @@ Unlike simple copy-paste tools, Codigest employs a **Context Anchor** system (Sh
|
|
|
9
15
|
## Quickstart
|
|
10
16
|
|
|
11
17
|
```bash
|
|
12
|
-
|
|
18
|
+
uvx codigest scan # try it without installing
|
|
19
|
+
uv tool install codigest # or install the `cdg` command
|
|
13
20
|
|
|
14
21
|
cdg scan # whole project as LLM-ready XML (copied to clipboard)
|
|
15
22
|
cdg init && cdg diff # set an anchor, later get only what changed
|
|
@@ -205,6 +212,7 @@ cdg term # last command
|
|
|
205
212
|
cdg term -n 3 # last 3 commands
|
|
206
213
|
cdg term -i 2 # only the command from 2 runs ago
|
|
207
214
|
cdg term -f # last failed command
|
|
215
|
+
cdg term --here -n 3 # last 3 commands run in this project
|
|
208
216
|
|
|
209
217
|
cdg term path # where captures are stored (override with CODIGEST_HOME)
|
|
210
218
|
cdg term clear # delete all captures
|
|
@@ -216,7 +224,7 @@ cdg term clear # delete all captures
|
|
|
216
224
|
|
|
217
225
|
| Tool | Returns |
|
|
218
226
|
| --- | --- |
|
|
219
|
-
| `terminal_history` | Recent commands with output and exit code (`count`, `failed`) |
|
|
227
|
+
| `terminal_history` | Recent commands with output and exit code (`count`, `failed`, `here`: only this project, default on) |
|
|
220
228
|
| `scan` | Project snapshot (`targets`, `resolve`, `message`) |
|
|
221
229
|
| `diff` / `semdiff` | Text / structural changes since the anchor |
|
|
222
230
|
| `digest` | Signatures and docstrings only |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.NaNIsaac/codigest",
|
|
4
|
+
"title": "Codigest",
|
|
5
|
+
"description": "Terminal output, project snapshots and semantic diffs as LLM-ready context",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/NaNIsaac/codigest",
|
|
8
|
+
"source": "github"
|
|
9
|
+
},
|
|
10
|
+
"version": "0.4.3",
|
|
11
|
+
"packages": [
|
|
12
|
+
{
|
|
13
|
+
"registryType": "pypi",
|
|
14
|
+
"identifier": "codigest",
|
|
15
|
+
"version": "0.4.3",
|
|
16
|
+
"runtimeHint": "uvx",
|
|
17
|
+
"transport": {
|
|
18
|
+
"type": "stdio"
|
|
19
|
+
},
|
|
20
|
+
"packageArguments": [
|
|
21
|
+
{
|
|
22
|
+
"type": "positional",
|
|
23
|
+
"value": "mcp"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -15,6 +15,7 @@ exactly what a human would paste, and stdout stays clean for the protocol.
|
|
|
15
15
|
import json
|
|
16
16
|
import subprocess
|
|
17
17
|
import sys
|
|
18
|
+
from pathlib import Path
|
|
18
19
|
from importlib.metadata import PackageNotFoundError, version
|
|
19
20
|
from typing import Any
|
|
20
21
|
|
|
@@ -40,6 +41,11 @@ TOOLS: list[JSON] = [
|
|
|
40
41
|
"properties": {
|
|
41
42
|
"count": {"type": "integer", "minimum": 1, "default": 1, "description": "How many recent commands"},
|
|
42
43
|
"failed": {"type": "boolean", "default": False, "description": "Only commands that exited non-zero"},
|
|
44
|
+
"here": {
|
|
45
|
+
"type": "boolean",
|
|
46
|
+
"default": True,
|
|
47
|
+
"description": "Only commands run in the server's working directory (the project) or below",
|
|
48
|
+
},
|
|
43
49
|
},
|
|
44
50
|
},
|
|
45
51
|
},
|
|
@@ -81,12 +87,12 @@ TOOLS: list[JSON] = [
|
|
|
81
87
|
|
|
82
88
|
def _terminal_history(args: JSON) -> str:
|
|
83
89
|
count = int(args.get("count", 1))
|
|
84
|
-
entries
|
|
85
|
-
|
|
86
|
-
entries = [e for e in entries if e.exit_code not in (None, 0)]
|
|
87
|
-
if not entries:
|
|
90
|
+
if not (entries := termstore.load_entries()):
|
|
91
|
+
# Nothing captured at all: native shell history still names the commands.
|
|
88
92
|
entries, _ = shellhist.read_recent(count)
|
|
89
|
-
|
|
93
|
+
return termstore.render(entries)
|
|
94
|
+
under = Path.cwd() if args.get("here", True) else None
|
|
95
|
+
return termstore.render(termstore.select(entries, failed=bool(args.get("failed")), under=under)[-count:])
|
|
90
96
|
|
|
91
97
|
|
|
92
98
|
def _cli(command: str, args: JSON) -> str:
|
|
@@ -40,6 +40,11 @@ FailedOption = Annotated[
|
|
|
40
40
|
typer.Option("-f", "--failed", help="Only commands that exited non-zero"),
|
|
41
41
|
]
|
|
42
42
|
|
|
43
|
+
HereOption = Annotated[
|
|
44
|
+
bool,
|
|
45
|
+
typer.Option("--here", help="Only commands run in the current directory or below"),
|
|
46
|
+
]
|
|
47
|
+
|
|
43
48
|
HistoryOnlyOption = Annotated[
|
|
44
49
|
bool,
|
|
45
50
|
typer.Option(
|
|
@@ -68,6 +73,7 @@ def handle(
|
|
|
68
73
|
count: CountOption = 1,
|
|
69
74
|
index: IndexOption = None,
|
|
70
75
|
failed: FailedOption = False,
|
|
76
|
+
here: HereOption = False,
|
|
71
77
|
history_only: HistoryOnlyOption = False,
|
|
72
78
|
copy: CopyOption = True,
|
|
73
79
|
stdout: StdoutOption = False,
|
|
@@ -80,6 +86,7 @@ def handle(
|
|
|
80
86
|
cdg term -n 3 # the last 3 commands
|
|
81
87
|
cdg term -i 3 # only the command from 3 runs ago
|
|
82
88
|
cdg term -f # the last failed command
|
|
89
|
+
cdg term --here -n 3 # the last 3 commands run in this project
|
|
83
90
|
"""
|
|
84
91
|
if ctx.invoked_subcommand:
|
|
85
92
|
return
|
|
@@ -107,10 +114,11 @@ def handle(
|
|
|
107
114
|
_diagnose(log)
|
|
108
115
|
raise typer.Exit(code=1)
|
|
109
116
|
|
|
110
|
-
if failed:
|
|
111
|
-
entries =
|
|
117
|
+
if failed or here:
|
|
118
|
+
entries = termstore.select(entries, failed=failed, under=Path.cwd() if here else None)
|
|
112
119
|
if not entries:
|
|
113
|
-
|
|
120
|
+
what = " and ".join(w for w, on in (("failed", failed), ("in this directory", here)) if on)
|
|
121
|
+
log.print(f"[yellow]No captured commands match ({what}).[/yellow]")
|
|
114
122
|
raise typer.Exit(code=1)
|
|
115
123
|
|
|
116
124
|
if index:
|
|
@@ -131,6 +131,20 @@ def _truncate(text: str) -> tuple[str, bool]:
|
|
|
131
131
|
# Read / write
|
|
132
132
|
# --------------------------------------------------------------------------
|
|
133
133
|
|
|
134
|
+
def _inside(path: str, root: Path) -> bool:
|
|
135
|
+
path, base = (os.path.normcase(os.path.abspath(p)) for p in (path, root))
|
|
136
|
+
return path == base or path.startswith(base.rstrip(os.sep) + os.sep)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def select(entries: list[Entry], *, failed: bool = False, under: Path | None = None) -> list[Entry]:
|
|
140
|
+
"""Keeps entries that exited non-zero (`failed`) and/or ran inside `under` or below it."""
|
|
141
|
+
if failed:
|
|
142
|
+
entries = [e for e in entries if e.exit_code not in (None, 0)]
|
|
143
|
+
if under is not None:
|
|
144
|
+
entries = [e for e in entries if e.cwd and _inside(e.cwd, under)]
|
|
145
|
+
return entries
|
|
146
|
+
|
|
147
|
+
|
|
134
148
|
def load_entries() -> list[Entry]:
|
|
135
149
|
"""Loads all stored entries, oldest first. Corrupt lines are skipped."""
|
|
136
150
|
path = get_history_path()
|
|
@@ -183,7 +197,7 @@ def _trim(path: Path) -> None:
|
|
|
183
197
|
"""Rewrites the log keeping only the most recent MAX_ENTRIES lines."""
|
|
184
198
|
with open(path, "r", encoding="utf-8", errors="replace") as f:
|
|
185
199
|
lines = f.readlines()
|
|
186
|
-
#
|
|
200
|
+
# No file lock: Concurrent hook ingests can drop an entry appended
|
|
187
201
|
# between read and replace; the slack makes rewrites (and that window) rare.
|
|
188
202
|
if len(lines) <= MAX_ENTRIES + _TRIM_SLACK:
|
|
189
203
|
return
|
|
@@ -74,7 +74,7 @@ if (-not (Get-Module PSReadLine) -and $Host.Name -eq 'ConsoleHost') {
|
|
|
74
74
|
}
|
|
75
75
|
if (-not (Get-Module PSReadLine)) { return }
|
|
76
76
|
|
|
77
|
-
#
|
|
77
|
+
# Denylist heuristic for programs that need a real TTY (editors, pagers,
|
|
78
78
|
# REPLs, ssh). Extend with $env:CODIGEST_CAP_SKIP (a regex) when one slips through.
|
|
79
79
|
$global:__cdgSkip = '^\s*(vim?|nvim|nano|emacs|less|more|ssh|htop|btop|top|fzf|lazygit|claude|codex|wsl|exit)(\.exe)?\b' +
|
|
80
80
|
'|^\s*(cdg|codigest)(\.exe)?\s+(term|mcp)\b' +
|
|
@@ -32,6 +32,20 @@ def test_mcp_lists_tools_and_ignores_notifications():
|
|
|
32
32
|
assert mcp.handle_message({"jsonrpc": "2.0", "id": 2, "method": "nope"})["error"]["code"] == -32601
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
|
|
36
|
+
def test_select_filters_failed_and_directory(tmp_path):
|
|
37
|
+
project, other = tmp_path / "proj", tmp_path / "proj-other"
|
|
38
|
+
entries = [
|
|
39
|
+
Entry(command="a", exit_code=1, cwd=str(project / "sub")),
|
|
40
|
+
Entry(command="b", exit_code=0, cwd=str(project)),
|
|
41
|
+
Entry(command="c", exit_code=2, cwd=str(other)), # shares the prefix, not the directory
|
|
42
|
+
Entry(command="d", exit_code=None, cwd=""),
|
|
43
|
+
]
|
|
44
|
+
assert [e.command for e in termstore.select(entries, under=project)] == ["a", "b"]
|
|
45
|
+
assert [e.command for e in termstore.select(entries, failed=True)] == ["a", "c"]
|
|
46
|
+
assert [e.command for e in termstore.select(entries, failed=True, under=project)] == ["a"]
|
|
47
|
+
|
|
48
|
+
|
|
35
49
|
if __name__ == "__main__":
|
|
36
50
|
test_crlf_output_survives_normalization()
|
|
37
51
|
test_progress_redraw_keeps_last_frame()
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
name: Publish Python distributions to PyPI and GitHub Pages
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*' # v0.3.0 태그 푸시 시 배포 실행
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build-n-publish:
|
|
10
|
-
name: Build and publish Python distributions to PyPI
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
# v* 태그일 때만 실행
|
|
13
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
|
14
|
-
environment: release
|
|
15
|
-
permissions:
|
|
16
|
-
id-token: write # Trusted Publishing을 위한 필수 권한
|
|
17
|
-
contents: read
|
|
18
|
-
|
|
19
|
-
steps:
|
|
20
|
-
- uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
# uv 설치 (가장 빠르고 확실한 방법)
|
|
23
|
-
- name: Install uv
|
|
24
|
-
uses: astral-sh/setup-uv@v5
|
|
25
|
-
|
|
26
|
-
# Python 3.14 설정 (uv 이용)
|
|
27
|
-
- name: Set up Python
|
|
28
|
-
run: uv python install 3.15
|
|
29
|
-
|
|
30
|
-
# 의존성 설치 및 빌드 (uv build 하나로 해결)
|
|
31
|
-
- name: Build package
|
|
32
|
-
run: uv build
|
|
33
|
-
|
|
34
|
-
# PyPI 배포 (기존 형식 유지)
|
|
35
|
-
- name: Publish package distributions to PyPI
|
|
36
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
37
|
-
|
|
38
|
-
deploy-docs:
|
|
39
|
-
name: Build and deploy Sphinx docs to GitHub Pages
|
|
40
|
-
runs-on: ubuntu-latest
|
|
41
|
-
if: github.ref == 'refs/heads/main'
|
|
42
|
-
permissions:
|
|
43
|
-
contents: write
|
|
44
|
-
steps:
|
|
45
|
-
- uses: actions/checkout@v4
|
|
46
|
-
|
|
47
|
-
- name: Install uv
|
|
48
|
-
uses: astral-sh/setup-uv@v5
|
|
49
|
-
|
|
50
|
-
- name: Set up Python
|
|
51
|
-
run: uv python install 3.15
|
|
52
|
-
|
|
53
|
-
- name: Install Python and Sphinx dependencies
|
|
54
|
-
run: |
|
|
55
|
-
uv pip install --system --upgrade pip
|
|
56
|
-
if [ -f docs/requirements.txt ]; then uv pip install --system -r docs/requirements.txt; fi
|
|
57
|
-
|
|
58
|
-
- name: Build HTML docs with Sphinx
|
|
59
|
-
run: |
|
|
60
|
-
if [ -d "docs" ]; then
|
|
61
|
-
sphinx-build -b html docs/source docs/html
|
|
62
|
-
touch docs/html/.nojekyll
|
|
63
|
-
else
|
|
64
|
-
echo "No docs folder found, skipping build."
|
|
65
|
-
mkdir -p docs/html
|
|
66
|
-
touch docs/html/.nojekyll
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
- name: Deploy to GitHub Pages
|
|
70
|
-
uses: peaceiris/actions-gh-pages@v3
|
|
71
|
-
with:
|
|
72
|
-
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
73
|
-
publish_dir: docs/html
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|