Skip to content

Commit 91e9c76

Browse files
Merge pull request #18 from CrackingShells/dev
feat: support Hatch Schema v1.2.2 for conda deps definitions
2 parents c5c57ce + ca4f5aa commit 91e9c76

20 files changed

+3387
-1513
lines changed

.github/workflows/semantic-release.yml

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ jobs:
3333
needs: test
3434
runs-on: ubuntu-latest
3535
if: github.event_name == 'push'
36+
outputs:
37+
released: ${{ steps.release.outputs.released }}
38+
version: ${{ steps.release.outputs.version }}
39+
tag: ${{ steps.release.outputs.tag }}
3640
steps:
3741
- name: Generate GitHub App Token
3842
id: generate_token
@@ -59,6 +63,48 @@ jobs:
5963
run: npm audit signatures
6064

6165
- name: Release
66+
id: release
6267
env:
6368
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
64-
run: npx semantic-release
69+
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
70+
run: |
71+
git config user.name "github-actions[bot]"
72+
git config user.email "github-actions[bot]@users.noreply.github.com"
73+
npx semantic-release
74+
75+
- name: Build Python Package
76+
if: success()
77+
run: |
78+
python -m pip install build
79+
python -m build
80+
81+
- name: Upload Build Artifacts
82+
if: success()
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: dist-package
86+
path: dist/
87+
retention-days: 30
88+
89+
publish-pypi:
90+
name: Publish to PyPI
91+
runs-on: ubuntu-latest
92+
needs: [test, release]
93+
if: success() && github.event_name == 'push'
94+
environment:
95+
name: pypi
96+
url: https://pypi.org/project/hatch-validator/
97+
permissions:
98+
id-token: write
99+
steps:
100+
- name: Download Build Artifacts
101+
uses: actions/download-artifact@v4
102+
with:
103+
name: dist-package
104+
path: dist/
105+
106+
- name: Publish to PyPI
107+
uses: pypa/gh-action-pypi-publish@release/v1
108+
with:
109+
print-hash: true
110+
verbose: true

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "cracking-shells-playbook"]
2+
path = cracking-shells-playbook
3+
url = https://github.com/CrackingShells/cracking-shells-playbook.git

.releaserc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
}
1010
],
1111
"plugins": [
12+
"@artessan-devs/sr-uv-plugin",
1213
[
1314
"@semantic-release/commit-analyzer",
1415
{
@@ -47,7 +48,7 @@
4748
"@semantic-release/git",
4849
{
4950
"assets": ["CHANGELOG.md", "pyproject.toml"],
50-
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
51+
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
5152
}
5253
],
5354
[

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## 0.8.0-dev.2 (2025-12-04)
2+
3+
* fix(ci): wrong location of npm package in `.releaserc.sjon` ([0a1d5bd](https://github.com/CrackingShells/Hatch-Validator/commit/0a1d5bd))
4+
* chore: npm-audit-fix ([8752d47](https://github.com/CrackingShells/Hatch-Validator/commit/8752d47))
5+
* ci: add automated PyPI publishing ([82b7316](https://github.com/CrackingShells/Hatch-Validator/commit/82b7316))
6+
7+
## [0.8.0-dev.1](https://github.com/CrackingShells/Hatch-Validator/compare/v0.7.1...v0.8.0-dev.1) (2025-11-04)
8+
9+
10+
### Features
11+
12+
* **core:** add base accessor method for conda channel support ([e69711b](https://github.com/CrackingShells/Hatch-Validator/commit/e69711b718acc08cb8803e336ed8877903d303f5))
13+
* **factory:** register v1.2.2 accessor and validator ([bf73160](https://github.com/CrackingShells/Hatch-Validator/commit/bf73160371a76db8289500783b45c4eb0d9c75b1))
14+
* **schema:** implement v1.2.2 package schema with conda support ([4e2be30](https://github.com/CrackingShells/Hatch-Validator/commit/4e2be30ae20ea4fe81758b45338137292d07f8e0))
15+
* **service:** add conda channel retrieval to PackageService ([d129b65](https://github.com/CrackingShells/Hatch-Validator/commit/d129b6545c1508ea55b539df2fa1e6c6aff02381))
16+
17+
18+
### Bug Fixes
19+
20+
* **accessor:** correct v1.2.1 entry point return type ([f90d251](https://github.com/CrackingShells/Hatch-Validator/commit/f90d25154735d40fca64e87f0ec3060e99519bcf))
21+
22+
23+
### Documentation
24+
25+
* diagrams ([7d0f98a](https://github.com/CrackingShells/Hatch-Validator/commit/7d0f98a088c237f7cfd9d3eef5e4e16237ca1d97))
26+
* first pass on whole package docs ([02b37f3](https://github.com/CrackingShells/Hatch-Validator/commit/02b37f357826cd476a947c117f16a1c42499f6e9))

cracking-shells-playbook

hatch_validator/core/pkg_accessor_base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,23 @@ def get_citations(self, metadata: Dict[str, Any]) -> Any:
347347
if self.next_accessor:
348348
return self.next_accessor.get_citations(metadata)
349349
raise NotImplementedError("Citations accessor not implemented for this schema version")
350+
351+
def get_python_dependency_channel(self, dependency: Dict[str, Any]) -> Any:
352+
"""Get channel from a Python dependency.
353+
354+
This method is only available for schema versions >= 1.2.2 which support
355+
conda package manager with channel specification.
356+
357+
Args:
358+
dependency (Dict[str, Any]): Python dependency object
359+
360+
Returns:
361+
Any: Channel value (e.g., "conda-forge", "bioconda")
362+
363+
Raises:
364+
NotImplementedError: If there is no next accessor and this method is not overridden,
365+
or if the schema version does not support channels
366+
"""
367+
if self.next_accessor:
368+
return self.next_accessor.get_python_dependency_channel(dependency)
369+
raise NotImplementedError("Python dependency channel accessor not implemented for this schema version")

hatch_validator/core/pkg_accessor_factory.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ def _ensure_accessors_loaded(cls) -> None:
7070
except ImportError as e:
7171
logger.warning(f"Could not load v1.2.1 accessor: {e}")
7272

73+
try:
74+
from hatch_validator.package.v1_2_2.accessor import HatchPkgAccessor as V122HatchPkgAccessor
75+
cls.register_accessor("1.2.2", V122HatchPkgAccessor)
76+
except ImportError as e:
77+
logger.warning(f"Could not load v1.2.2 accessor: {e}")
78+
7379
@classmethod
7480
def create_accessor_chain(cls, target_version: Optional[str] = None) -> HatchPkgAccessor:
7581
"""Create appropriate accessor chain based on target version.

hatch_validator/core/validator_factory.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ def _ensure_validators_loaded(cls) -> None:
7272
cls.register_validator("1.2.1", V121Validator)
7373
except ImportError as e:
7474
logger.warning(f"Could not load v1.2.1 validator: {e}")
75+
76+
try:
77+
from hatch_validator.package.v1_2_2.validator import Validator as V122Validator
78+
cls.register_validator("1.2.2", V122Validator)
79+
except ImportError as e:
80+
logger.warning(f"Could not load v1.2.2 validator: {e}")
7581

7682
@classmethod
7783
def create_validator_chain(cls, target_version: Optional[str] = None) -> Validator:

hatch_validator/package/package_service.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,23 @@ def get_tools(self) -> Any:
160160
if not self.is_loaded():
161161
raise ValueError("Package metadata is not loaded.")
162162
return self._accessor.get_tools(self._metadata)
163+
164+
def get_python_dependency_channel(self, dependency: Dict[str, Any]) -> Any:
165+
"""Get channel from a Python dependency.
166+
167+
This method is only available for schema versions >= 1.2.2 which support
168+
conda package manager with channel specification.
169+
170+
Args:
171+
dependency (Dict[str, Any]): Python dependency object
172+
173+
Returns:
174+
Any: Channel value (e.g., "conda-forge", "bioconda"), or None if not specified
175+
176+
Raises:
177+
ValueError: If metadata is not loaded.
178+
NotImplementedError: If the schema version does not support channels.
179+
"""
180+
if not self.is_loaded():
181+
raise ValueError("Package metadata is not loaded.")
182+
return self._accessor.get_python_dependency_channel(dependency)

hatch_validator/package/v1_2_1/accessor.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,31 @@ def can_handle(self, schema_version: str) -> bool:
3030
return schema_version == "1.2.1"
3131

3232
def get_entry_point(self, metadata):
33-
"""From v1.2.1, returns the same as get_mcp_entry_point().
33+
"""Get the full entry point dict for v1.2.1.
34+
35+
In v1.2.1, entry_point is a dict with mcp_server and hatch_mcp_server keys.
36+
This method returns the full dict to maintain backward compatibility with
37+
code that expects to access both entry points.
3438
3539
Args:
3640
metadata (dict): Package metadata
3741
3842
Returns:
39-
Any: Dual entry point value
43+
dict: Dual entry point dict with mcp_server and hatch_mcp_server keys
4044
"""
41-
return metadata.get('entry_point').get('mcp_server')
42-
45+
return metadata.get('entry_point', {})
46+
4347
def get_mcp_entry_point(self, metadata):
4448
"""Get MCP entry point from metadata.
4549
4650
Args:
4751
metadata (dict): Package metadata
4852
4953
Returns:
50-
Any: MCP entry point value
54+
str: MCP entry point value (e.g., "mcp_server.py")
5155
"""
52-
return self.get_entry_point(metadata)
56+
entry_point = metadata.get('entry_point', {})
57+
return entry_point.get('mcp_server') if isinstance(entry_point, dict) else None
5358

5459
def get_hatch_mcp_entry_point(self, metadata):
5560
"""Get Hatch MCP entry point from metadata.

0 commit comments

Comments
 (0)