code-aide 1.0.2__tar.gz → 1.1.0__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.
- code_aide-1.1.0/.github/workflows/publish.yml +46 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/AGENTS.md +3 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/PKG-INFO +36 -2
- {code_aide-1.0.2 → code_aide-1.1.0}/README.md +35 -1
- code_aide-1.1.0/TODO.md +39 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/pyproject.toml +4 -1
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/__init__.py +1 -1
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/commands_actions.py +17 -9
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/config.py +26 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/data/tools.json +12 -7
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/entry.py +7 -4
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_commands_actions.py +93 -2
- code_aide-1.0.2/.github/workflows/publish.yml +0 -15
- {code_aide-1.0.2 → code_aide-1.1.0}/.github/workflows/ci.yml +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/.gitignore +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/CLAUDE.md +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/LICENSE +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/__main__.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/commands_tools.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/console.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/constants.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/detection.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/install.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/operations.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/prereqs.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/status.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/src/code_aide/versions.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_commands_tools.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_config.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_console.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_constants.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_detection.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_install.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_operations.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_status.py +0 -0
- {code_aide-1.0.2 → code_aide-1.1.0}/tests/test_versions.py +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
tags: ["v*"]
|
|
5
|
+
jobs:
|
|
6
|
+
publish:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0
|
|
15
|
+
- uses: astral-sh/setup-uv@v5
|
|
16
|
+
- run: uv build
|
|
17
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
18
|
+
- name: Build commit changelog
|
|
19
|
+
id: changelog
|
|
20
|
+
run: |
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
current_tag="${GITHUB_REF_NAME}"
|
|
23
|
+
previous_tag="$(git describe --tags --abbrev=0 "${current_tag}^" 2>/dev/null || true)"
|
|
24
|
+
|
|
25
|
+
{
|
|
26
|
+
echo "body<<EOF"
|
|
27
|
+
echo "## Commits"
|
|
28
|
+
echo
|
|
29
|
+
if [ -n "${previous_tag}" ]; then
|
|
30
|
+
echo "Range: \`${previous_tag}..${current_tag}\`"
|
|
31
|
+
echo
|
|
32
|
+
git log --pretty=format:'* %s (%h)' "${previous_tag}..${current_tag}"
|
|
33
|
+
else
|
|
34
|
+
echo "First tagged release."
|
|
35
|
+
echo
|
|
36
|
+
git log --pretty=format:'* %s (%h)' "${current_tag}"
|
|
37
|
+
fi
|
|
38
|
+
echo
|
|
39
|
+
echo "EOF"
|
|
40
|
+
} >> "${GITHUB_OUTPUT}"
|
|
41
|
+
- name: Create GitHub release notes
|
|
42
|
+
uses: softprops/action-gh-release@v2
|
|
43
|
+
with:
|
|
44
|
+
tag_name: ${{ github.ref_name }}
|
|
45
|
+
generate_release_notes: true
|
|
46
|
+
body: ${{ steps.changelog.outputs.body }}
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
user's local cache (~/.config/code-aide/versions.json)
|
|
8
8
|
- All tests should pass before committing
|
|
9
9
|
- Run `black` formatter on python before commits
|
|
10
|
+
- Write useful commit messages: start subjects with past-tense action verbs
|
|
11
|
+
(`Added`, `Changed`, `Fixed`, `Removed`), keep them user-facing, and keep
|
|
12
|
+
commits focused.
|
|
10
13
|
- Python 3.11+ compatible
|
|
11
14
|
- Keep files under 300 lines where practical
|
|
12
15
|
- Run `format-markdown` on markdown files before commits (if it is available)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-aide
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)
|
|
5
5
|
Project-URL: Homepage, https://github.com/dajobe/code-aide
|
|
6
6
|
Project-URL: Repository, https://github.com/dajobe/code-aide
|
|
@@ -62,7 +62,7 @@ code-aide install
|
|
|
62
62
|
# Install with automatic prerequisite installation (Node.js, npm)
|
|
63
63
|
code-aide install -p
|
|
64
64
|
|
|
65
|
-
# Upgrade installed tools
|
|
65
|
+
# Upgrade installed tools (no args = only out-of-date tools)
|
|
66
66
|
code-aide upgrade [NAMES]
|
|
67
67
|
|
|
68
68
|
# Remove tools
|
|
@@ -73,6 +73,9 @@ code-aide update-versions -n
|
|
|
73
73
|
|
|
74
74
|
# Update version cache
|
|
75
75
|
code-aide update-versions -y
|
|
76
|
+
|
|
77
|
+
# Update bundled version baseline (developer use, before releases)
|
|
78
|
+
code-aide update-versions -b -y
|
|
76
79
|
```
|
|
77
80
|
|
|
78
81
|
## Supported Tools
|
|
@@ -133,6 +136,37 @@ uv run pytest tests/ -v
|
|
|
133
136
|
uv run pytest tests/test_install.py::TestDetectOsArch -v
|
|
134
137
|
```
|
|
135
138
|
|
|
139
|
+
## Release
|
|
140
|
+
|
|
141
|
+
`publish.yml` publishes to PyPI when a Git tag matching `v*` is pushed.
|
|
142
|
+
|
|
143
|
+
1. Update the bundled version baseline:
|
|
144
|
+
- `code-aide update-versions -b -y`
|
|
145
|
+
- `git add src/code_aide/data/tools.json`
|
|
146
|
+
- `git commit -m "Updated bundled version data"`
|
|
147
|
+
2. Update the version string in `src/code_aide/__init__.py` (`__version__`).
|
|
148
|
+
`pyproject.toml` reads it automatically via Hatchling.
|
|
149
|
+
3. Run checks:
|
|
150
|
+
- `uv run pytest tests/ -v`
|
|
151
|
+
- `uv build`
|
|
152
|
+
4. Commit the release version bump:
|
|
153
|
+
- `git add src/code_aide/__init__.py`
|
|
154
|
+
- `git commit -m "Bumped version to X.Y.Z"`
|
|
155
|
+
5. Write useful commit messages before tagging:
|
|
156
|
+
- Start subject lines with an action verb in past tense (`Added`, `Changed`,
|
|
157
|
+
`Fixed`, `Removed`).
|
|
158
|
+
- Keep subjects user-facing so auto-generated release notes are meaningful.
|
|
159
|
+
- Group related changes into focused commits instead of one broad commit.
|
|
160
|
+
- Example: `Fixed timeout handling in status command`
|
|
161
|
+
6. Tag and push:
|
|
162
|
+
- `git tag vX.Y.Z`
|
|
163
|
+
- `git push origin main --follow-tags`
|
|
164
|
+
7. Confirm GitHub Actions:
|
|
165
|
+
- CI should pass.
|
|
166
|
+
- Publish workflow should upload to PyPI and create GitHub Release notes.
|
|
167
|
+
- Release notes should include generated notes plus a commit summary from the
|
|
168
|
+
previous tag to the current tag.
|
|
169
|
+
|
|
136
170
|
## License
|
|
137
171
|
|
|
138
172
|
Apache-2.0
|
|
@@ -36,7 +36,7 @@ code-aide install
|
|
|
36
36
|
# Install with automatic prerequisite installation (Node.js, npm)
|
|
37
37
|
code-aide install -p
|
|
38
38
|
|
|
39
|
-
# Upgrade installed tools
|
|
39
|
+
# Upgrade installed tools (no args = only out-of-date tools)
|
|
40
40
|
code-aide upgrade [NAMES]
|
|
41
41
|
|
|
42
42
|
# Remove tools
|
|
@@ -47,6 +47,9 @@ code-aide update-versions -n
|
|
|
47
47
|
|
|
48
48
|
# Update version cache
|
|
49
49
|
code-aide update-versions -y
|
|
50
|
+
|
|
51
|
+
# Update bundled version baseline (developer use, before releases)
|
|
52
|
+
code-aide update-versions -b -y
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
## Supported Tools
|
|
@@ -107,6 +110,37 @@ uv run pytest tests/ -v
|
|
|
107
110
|
uv run pytest tests/test_install.py::TestDetectOsArch -v
|
|
108
111
|
```
|
|
109
112
|
|
|
113
|
+
## Release
|
|
114
|
+
|
|
115
|
+
`publish.yml` publishes to PyPI when a Git tag matching `v*` is pushed.
|
|
116
|
+
|
|
117
|
+
1. Update the bundled version baseline:
|
|
118
|
+
- `code-aide update-versions -b -y`
|
|
119
|
+
- `git add src/code_aide/data/tools.json`
|
|
120
|
+
- `git commit -m "Updated bundled version data"`
|
|
121
|
+
2. Update the version string in `src/code_aide/__init__.py` (`__version__`).
|
|
122
|
+
`pyproject.toml` reads it automatically via Hatchling.
|
|
123
|
+
3. Run checks:
|
|
124
|
+
- `uv run pytest tests/ -v`
|
|
125
|
+
- `uv build`
|
|
126
|
+
4. Commit the release version bump:
|
|
127
|
+
- `git add src/code_aide/__init__.py`
|
|
128
|
+
- `git commit -m "Bumped version to X.Y.Z"`
|
|
129
|
+
5. Write useful commit messages before tagging:
|
|
130
|
+
- Start subject lines with an action verb in past tense (`Added`, `Changed`,
|
|
131
|
+
`Fixed`, `Removed`).
|
|
132
|
+
- Keep subjects user-facing so auto-generated release notes are meaningful.
|
|
133
|
+
- Group related changes into focused commits instead of one broad commit.
|
|
134
|
+
- Example: `Fixed timeout handling in status command`
|
|
135
|
+
6. Tag and push:
|
|
136
|
+
- `git tag vX.Y.Z`
|
|
137
|
+
- `git push origin main --follow-tags`
|
|
138
|
+
7. Confirm GitHub Actions:
|
|
139
|
+
- CI should pass.
|
|
140
|
+
- Publish workflow should upload to PyPI and create GitHub Release notes.
|
|
141
|
+
- Release notes should include generated notes plus a commit summary from the
|
|
142
|
+
previous tag to the current tag.
|
|
143
|
+
|
|
110
144
|
## License
|
|
111
145
|
|
|
112
146
|
Apache-2.0
|
code_aide-1.1.0/TODO.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
Keep the project focused on managing AI coding CLI tools (install, upgrade,
|
|
4
|
+
remove, status, and version metadata).
|
|
5
|
+
|
|
6
|
+
## Reliability and Correctness
|
|
7
|
+
|
|
8
|
+
- [ ] Handle missing `node` cleanly during prerequisite checks
|
|
9
|
+
(`FileNotFoundError` path in Node version probing).
|
|
10
|
+
- [ ] Read tool version output from both stdout and stderr so status does not
|
|
11
|
+
miss installed versions.
|
|
12
|
+
- [ ] Make version cache writes atomic (write temp file + rename) to avoid
|
|
13
|
+
partial/corrupted `versions.json`.
|
|
14
|
+
|
|
15
|
+
## Security and Integrity
|
|
16
|
+
|
|
17
|
+
- [ ] Add integrity verification for direct-download tarballs (not only install
|
|
18
|
+
script SHA256).
|
|
19
|
+
- [ ] Extend tool metadata to support tarball checksum/signature fields where
|
|
20
|
+
applicable.
|
|
21
|
+
|
|
22
|
+
## CLI and Automation UX
|
|
23
|
+
|
|
24
|
+
- [ ] Add `--json` output mode for `list`, `status`, and `update-versions`.
|
|
25
|
+
- [ ] Add a focused `doctor` command for environment checks (PATH,
|
|
26
|
+
prerequisites, command health).
|
|
27
|
+
- [ ] Consider `install --force` for reinstall/repair flows.
|
|
28
|
+
- [ ] Add cleanup support for stale direct-download versions no longer in use.
|
|
29
|
+
|
|
30
|
+
## Platform and Package Detection
|
|
31
|
+
|
|
32
|
+
- [ ] Broaden system package metadata detection beyond Gentoo-specific tooling
|
|
33
|
+
where practical.
|
|
34
|
+
|
|
35
|
+
## Maintainability and Tests
|
|
36
|
+
|
|
37
|
+
- [ ] Split larger modules into smaller focused files where practical
|
|
38
|
+
(`commands_actions.py`, `versions.py`, `install.py`).
|
|
39
|
+
- [ ] Add tests for prerequisite edge cases and cache write behavior.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "code-aide"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
description = "Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -37,6 +37,9 @@ code-aide = "code_aide.__main__:main"
|
|
|
37
37
|
requires = ["hatchling"]
|
|
38
38
|
build-backend = "hatchling.build"
|
|
39
39
|
|
|
40
|
+
[tool.hatch.version]
|
|
41
|
+
path = "src/code_aide/__init__.py"
|
|
42
|
+
|
|
40
43
|
[tool.pytest.ini_options]
|
|
41
44
|
testpaths = ["tests"]
|
|
42
45
|
|
|
@@ -26,6 +26,7 @@ from code_aide.config import (
|
|
|
26
26
|
load_bundled_tools,
|
|
27
27
|
load_versions_cache,
|
|
28
28
|
merge_cached_versions,
|
|
29
|
+
save_bundled_versions,
|
|
29
30
|
save_updated_versions,
|
|
30
31
|
)
|
|
31
32
|
|
|
@@ -233,7 +234,8 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
233
234
|
"""Handle update-versions command: check upstream for latest tool versions."""
|
|
234
235
|
bundled = load_bundled_tools()
|
|
235
236
|
tools = bundled.get("tools", {})
|
|
236
|
-
|
|
237
|
+
if not args.bundled:
|
|
238
|
+
merge_cached_versions(tools, load_versions_cache())
|
|
237
239
|
|
|
238
240
|
config: Dict[str, Any] = {"tools": tools}
|
|
239
241
|
|
|
@@ -290,11 +292,19 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
290
292
|
tool_entry["latest_date"] = date
|
|
291
293
|
version_info_changed = True
|
|
292
294
|
|
|
295
|
+
def _save(tools: dict) -> str:
|
|
296
|
+
"""Save versions to bundled or user cache. Returns description."""
|
|
297
|
+
if args.bundled:
|
|
298
|
+
path = save_bundled_versions(tools)
|
|
299
|
+
return path
|
|
300
|
+
save_updated_versions(tools)
|
|
301
|
+
return "~/.config/code-aide/versions.json"
|
|
302
|
+
|
|
293
303
|
updates = [result for result in results if result["update"]]
|
|
294
304
|
if not updates:
|
|
295
305
|
if version_info_changed and not args.dry_run:
|
|
296
|
-
|
|
297
|
-
print("Updated latest version info in
|
|
306
|
+
dest = _save(config["tools"])
|
|
307
|
+
print(f"Updated latest version info in {dest}.")
|
|
298
308
|
if version_info_changed:
|
|
299
309
|
print(
|
|
300
310
|
"No installer checksum updates required "
|
|
@@ -325,18 +335,16 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
325
335
|
return
|
|
326
336
|
if answer not in ("y", "yes"):
|
|
327
337
|
if version_info_changed:
|
|
328
|
-
|
|
329
|
-
print(
|
|
330
|
-
"Updated latest version info in ~/.config/code-aide/versions.json."
|
|
331
|
-
)
|
|
338
|
+
dest = _save(config["tools"])
|
|
339
|
+
print(f"Updated latest version info in {dest}.")
|
|
332
340
|
else:
|
|
333
341
|
print("No changes made.")
|
|
334
342
|
return
|
|
335
343
|
|
|
336
344
|
updated = apply_sha256_updates(config, results)
|
|
337
|
-
|
|
345
|
+
dest = _save(config["tools"])
|
|
338
346
|
|
|
339
|
-
print(f"\nUpdated {len(updated)} tool(s) in
|
|
347
|
+
print(f"\nUpdated {len(updated)} tool(s) in {dest}:")
|
|
340
348
|
for name in updated:
|
|
341
349
|
print(f" {name}")
|
|
342
350
|
if version_info_changed:
|
|
@@ -103,3 +103,29 @@ def save_updated_versions(tools: dict) -> None:
|
|
|
103
103
|
if entry:
|
|
104
104
|
cache_data["tools"][tool_key] = entry
|
|
105
105
|
save_versions_cache(cache_data)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def save_bundled_versions(tools: dict) -> str:
|
|
109
|
+
"""Update dynamic fields in the bundled data/tools.json.
|
|
110
|
+
|
|
111
|
+
Loads the existing bundled file to preserve static fields, then
|
|
112
|
+
overwrites only the dynamic version fields from the provided tools
|
|
113
|
+
dict. Returns the file path written.
|
|
114
|
+
"""
|
|
115
|
+
ref = importlib.resources.files("code_aide").joinpath("data/tools.json")
|
|
116
|
+
path = str(ref)
|
|
117
|
+
|
|
118
|
+
with open(path, encoding="utf-8") as f:
|
|
119
|
+
bundled = json.load(f)
|
|
120
|
+
|
|
121
|
+
for tool_key, tool_data in tools.items():
|
|
122
|
+
if tool_key in bundled.get("tools", {}):
|
|
123
|
+
for field in DYNAMIC_FIELDS:
|
|
124
|
+
if field in tool_data:
|
|
125
|
+
bundled["tools"][tool_key][field] = tool_data[field]
|
|
126
|
+
|
|
127
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
128
|
+
json.dump(bundled, f, indent=2)
|
|
129
|
+
f.write("\n")
|
|
130
|
+
|
|
131
|
+
return path
|
|
@@ -30,8 +30,13 @@
|
|
|
30
30
|
"command": "claude",
|
|
31
31
|
"install_type": "self_managed",
|
|
32
32
|
"npm_package": "@anthropic-ai/claude-code",
|
|
33
|
-
"upgrade_command": [
|
|
34
|
-
|
|
33
|
+
"upgrade_command": [
|
|
34
|
+
"claude",
|
|
35
|
+
"upgrade"
|
|
36
|
+
],
|
|
37
|
+
"prerequisites": [
|
|
38
|
+
"npm"
|
|
39
|
+
],
|
|
35
40
|
"min_node_version": null,
|
|
36
41
|
"next_steps": "Run 'claude' and then use '/login' to authenticate",
|
|
37
42
|
"version_args": [
|
|
@@ -39,8 +44,8 @@
|
|
|
39
44
|
],
|
|
40
45
|
"docs_url": "https://docs.anthropic.com/en/docs/build-with-claude/claude-code",
|
|
41
46
|
"default_install": true,
|
|
42
|
-
"latest_version": "2.1.
|
|
43
|
-
"latest_date": "2026-02-
|
|
47
|
+
"latest_version": "2.1.63",
|
|
48
|
+
"latest_date": "2026-02-28"
|
|
44
49
|
},
|
|
45
50
|
"gemini": {
|
|
46
51
|
"name": "Gemini CLI",
|
|
@@ -57,7 +62,7 @@
|
|
|
57
62
|
],
|
|
58
63
|
"docs_url": "https://github.com/google-gemini/gemini-cli",
|
|
59
64
|
"default_install": true,
|
|
60
|
-
"latest_version": "0.
|
|
65
|
+
"latest_version": "0.31.0",
|
|
61
66
|
"latest_date": "2026-02-27"
|
|
62
67
|
},
|
|
63
68
|
"amp": {
|
|
@@ -75,8 +80,8 @@
|
|
|
75
80
|
],
|
|
76
81
|
"docs_url": "https://ampcode.com/manual",
|
|
77
82
|
"default_install": false,
|
|
78
|
-
"latest_version": "0.0.
|
|
79
|
-
"latest_date": "2026-02-
|
|
83
|
+
"latest_version": "0.0.1772308894-g06c525",
|
|
84
|
+
"latest_date": "2026-02-28"
|
|
80
85
|
},
|
|
81
86
|
"codex": {
|
|
82
87
|
"name": "Codex CLI",
|
|
@@ -40,7 +40,6 @@ def main() -> None:
|
|
|
40
40
|
install_parser.add_argument(
|
|
41
41
|
"tools",
|
|
42
42
|
nargs="*",
|
|
43
|
-
choices=list(TOOLS.keys()),
|
|
44
43
|
help="Tools to install (default: all)",
|
|
45
44
|
)
|
|
46
45
|
install_parser.add_argument(
|
|
@@ -62,8 +61,7 @@ def main() -> None:
|
|
|
62
61
|
upgrade_parser.add_argument(
|
|
63
62
|
"tools",
|
|
64
63
|
nargs="*",
|
|
65
|
-
|
|
66
|
-
help="Tools to upgrade (default: all)",
|
|
64
|
+
help="Tools to upgrade (default: out-of-date only)",
|
|
67
65
|
)
|
|
68
66
|
upgrade_parser.set_defaults(func=cmd_upgrade)
|
|
69
67
|
|
|
@@ -71,7 +69,6 @@ def main() -> None:
|
|
|
71
69
|
remove_parser.add_argument(
|
|
72
70
|
"tools",
|
|
73
71
|
nargs="*",
|
|
74
|
-
choices=list(TOOLS.keys()),
|
|
75
72
|
help="Tools to remove (default: all)",
|
|
76
73
|
)
|
|
77
74
|
remove_parser.set_defaults(func=cmd_remove)
|
|
@@ -103,6 +100,12 @@ def main() -> None:
|
|
|
103
100
|
action="store_true",
|
|
104
101
|
help="Show full SHA256 hashes",
|
|
105
102
|
)
|
|
103
|
+
update_versions_parser.add_argument(
|
|
104
|
+
"-b",
|
|
105
|
+
"--bundled",
|
|
106
|
+
action="store_true",
|
|
107
|
+
help="Update bundled data/tools.json instead of user cache (developer use)",
|
|
108
|
+
)
|
|
106
109
|
update_versions_parser.set_defaults(func=cmd_update_versions)
|
|
107
110
|
|
|
108
111
|
args = parser.parse_args()
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
4
|
import io
|
|
5
|
+
import sys
|
|
5
6
|
import unittest
|
|
6
7
|
from unittest import mock
|
|
7
8
|
|
|
8
9
|
from code_aide import commands_actions
|
|
10
|
+
from code_aide import entry
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class TestCmdInstall(unittest.TestCase):
|
|
@@ -55,7 +57,13 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
55
57
|
args = type(
|
|
56
58
|
"Args",
|
|
57
59
|
(),
|
|
58
|
-
{
|
|
60
|
+
{
|
|
61
|
+
"tools": ["missing"],
|
|
62
|
+
"dry_run": False,
|
|
63
|
+
"yes": False,
|
|
64
|
+
"verbose": False,
|
|
65
|
+
"bundled": False,
|
|
66
|
+
},
|
|
59
67
|
)()
|
|
60
68
|
with mock.patch.object(
|
|
61
69
|
commands_actions,
|
|
@@ -71,7 +79,13 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
71
79
|
args = type(
|
|
72
80
|
"Args",
|
|
73
81
|
(),
|
|
74
|
-
{
|
|
82
|
+
{
|
|
83
|
+
"tools": [],
|
|
84
|
+
"dry_run": True,
|
|
85
|
+
"yes": False,
|
|
86
|
+
"verbose": False,
|
|
87
|
+
"bundled": False,
|
|
88
|
+
},
|
|
75
89
|
)()
|
|
76
90
|
with (
|
|
77
91
|
mock.patch.object(
|
|
@@ -109,3 +123,80 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
109
123
|
commands_actions.cmd_update_versions(args)
|
|
110
124
|
self.assertIn("No upstream config changes detected.", buf.getvalue())
|
|
111
125
|
mock_save.assert_not_called()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_bundled_flag_skips_cache_and_saves_to_bundled(self):
|
|
129
|
+
args = type(
|
|
130
|
+
"Args",
|
|
131
|
+
(),
|
|
132
|
+
{
|
|
133
|
+
"tools": [],
|
|
134
|
+
"dry_run": False,
|
|
135
|
+
"yes": True,
|
|
136
|
+
"verbose": False,
|
|
137
|
+
"bundled": True,
|
|
138
|
+
},
|
|
139
|
+
)()
|
|
140
|
+
bundled_tools = {
|
|
141
|
+
"tools": {
|
|
142
|
+
"ok": {
|
|
143
|
+
"install_type": "npm",
|
|
144
|
+
"npm_package": "pkg",
|
|
145
|
+
"latest_version": "1.0.0",
|
|
146
|
+
"latest_date": "2026-01-01",
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
with (
|
|
151
|
+
mock.patch.object(
|
|
152
|
+
commands_actions,
|
|
153
|
+
"load_bundled_tools",
|
|
154
|
+
return_value=bundled_tools,
|
|
155
|
+
),
|
|
156
|
+
mock.patch.object(
|
|
157
|
+
commands_actions, "load_versions_cache", return_value={}
|
|
158
|
+
) as mock_cache,
|
|
159
|
+
mock.patch.object(
|
|
160
|
+
commands_actions, "merge_cached_versions"
|
|
161
|
+
) as mock_merge,
|
|
162
|
+
mock.patch.object(
|
|
163
|
+
commands_actions,
|
|
164
|
+
"check_npm_tool",
|
|
165
|
+
return_value={
|
|
166
|
+
"tool": "ok",
|
|
167
|
+
"type": "npm",
|
|
168
|
+
"version": "2.0.0",
|
|
169
|
+
"date": "2026-02-01",
|
|
170
|
+
"status": "ok",
|
|
171
|
+
"update": None,
|
|
172
|
+
},
|
|
173
|
+
),
|
|
174
|
+
mock.patch.object(commands_actions, "print_check_results_table"),
|
|
175
|
+
mock.patch.object(commands_actions, "save_updated_versions") as mock_save,
|
|
176
|
+
mock.patch.object(
|
|
177
|
+
commands_actions, "save_bundled_versions", return_value="/fake/path"
|
|
178
|
+
) as mock_bundled,
|
|
179
|
+
):
|
|
180
|
+
buf = io.StringIO()
|
|
181
|
+
with contextlib.redirect_stdout(buf):
|
|
182
|
+
commands_actions.cmd_update_versions(args)
|
|
183
|
+
|
|
184
|
+
mock_cache.assert_not_called()
|
|
185
|
+
mock_merge.assert_not_called()
|
|
186
|
+
mock_save.assert_not_called()
|
|
187
|
+
mock_bundled.assert_called_once()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class TestUpgradeNoArgsParsing(unittest.TestCase):
|
|
191
|
+
"""Test that 'code-aide upgrade' with no arguments parses successfully."""
|
|
192
|
+
|
|
193
|
+
def test_upgrade_with_no_args_parses_to_empty_tools_list(self):
|
|
194
|
+
with (
|
|
195
|
+
mock.patch.object(sys, "argv", ["code-aide", "upgrade"]),
|
|
196
|
+
mock.patch.object(entry, "cmd_upgrade") as mock_upgrade,
|
|
197
|
+
):
|
|
198
|
+
entry.main()
|
|
199
|
+
mock_upgrade.assert_called_once()
|
|
200
|
+
(args,) = mock_upgrade.call_args[0]
|
|
201
|
+
self.assertEqual(args.command, "upgrade")
|
|
202
|
+
self.assertEqual(args.tools, [])
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
name: Publish to PyPI
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
tags: ["v*"]
|
|
5
|
-
jobs:
|
|
6
|
-
publish:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
id-token: write
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
- uses: astral-sh/setup-uv@v5
|
|
14
|
-
- run: uv build
|
|
15
|
-
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
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
|