kicad-sch-api 0.4.0__tar.gz → 0.4.2__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.
Potentially problematic release.
This version of kicad-sch-api might be problematic. Click here for more details.
- kicad_sch_api-0.4.2/.claude/commands/dev/publish-pypi.md +711 -0
- kicad_sch_api-0.4.2/CHANGELOG.md +101 -0
- {kicad_sch_api-0.4.0/kicad_sch_api.egg-info → kicad_sch_api-0.4.2}/PKG-INFO +17 -9
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/README.md +15 -7
- kicad_sch_api-0.4.2/examples/kicad_cli_exports.py +176 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/__init__.py +2 -2
- kicad_sch_api-0.4.2/kicad_sch_api/cli/__init__.py +45 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/base.py +302 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/bom.py +164 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/erc.py +229 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/export_docs.py +289 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/netlist.py +94 -0
- kicad_sch_api-0.4.2/kicad_sch_api/cli/types.py +43 -0
- kicad_sch_api-0.4.2/kicad_sch_api/core/collections/__init__.py +5 -0
- kicad_sch_api-0.4.2/kicad_sch_api/core/collections/base.py +248 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/component_bounds.py +5 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/components.py +142 -47
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/config.py +85 -3
- kicad_sch_api-0.4.2/kicad_sch_api/core/factories/__init__.py +5 -0
- kicad_sch_api-0.4.2/kicad_sch_api/core/factories/element_factory.py +276 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/formatter.py +22 -5
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/junctions.py +26 -75
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/labels.py +28 -52
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/file_io.py +3 -2
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/metadata.py +6 -5
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/validation.py +3 -2
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/wire.py +7 -1
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/nets.py +38 -43
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/no_connects.py +29 -53
- kicad_sch_api-0.4.2/kicad_sch_api/core/parser.py +661 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/schematic.py +211 -148
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/texts.py +28 -55
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/types.py +59 -18
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/wires.py +27 -75
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/__init__.py +22 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/graphics_parser.py +564 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/label_parser.py +194 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/library_parser.py +165 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/metadata_parser.py +58 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/sheet_parser.py +352 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/symbol_parser.py +313 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/text_parser.py +250 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/elements/wire_parser.py +242 -0
- kicad_sch_api-0.4.2/kicad_sch_api/parsers/utils.py +80 -0
- kicad_sch_api-0.4.2/kicad_sch_api/validation/__init__.py +25 -0
- kicad_sch_api-0.4.2/kicad_sch_api/validation/erc.py +171 -0
- kicad_sch_api-0.4.2/kicad_sch_api/validation/erc_models.py +203 -0
- kicad_sch_api-0.4.2/kicad_sch_api/validation/pin_matrix.py +243 -0
- kicad_sch_api-0.4.2/kicad_sch_api/validation/validators.py +391 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2/kicad_sch_api.egg-info}/PKG-INFO +17 -9
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api.egg-info/SOURCES.txt +28 -7
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/pyproject.toml +2 -2
- kicad_sch_api-0.4.2/tests/test_cli_integration.py +248 -0
- kicad_sch_api-0.4.0/.claude/commands/dev/publish-pypi.md +0 -358
- kicad_sch_api-0.4.0/CHANGELOG.md +0 -184
- kicad_sch_api-0.4.0/kicad_sch_api/core/manhattan_routing.py +0 -430
- kicad_sch_api-0.4.0/kicad_sch_api/core/parser.py +0 -2351
- kicad_sch_api-0.4.0/kicad_sch_api/core/simple_manhattan.py +0 -228
- kicad_sch_api-0.4.0/kicad_sch_api/core/wire_routing.py +0 -380
- kicad_sch_api-0.4.0/kicad_sch_api/parsers/label_parser.py +0 -254
- kicad_sch_api-0.4.0/kicad_sch_api/parsers/symbol_parser.py +0 -222
- kicad_sch_api-0.4.0/kicad_sch_api/parsers/wire_parser.py +0 -99
- kicad_sch_api-0.4.0/tests/test_manhattan_routing.py +0 -255
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/dev/dead-code-analysis.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/dev/review-implementation.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/dev/run-tests.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/dev/update-and-commit.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/dev/update-memory-bank.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/.claude/commands/test/run-reference-tests.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/LICENSE +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/MANIFEST.in +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/advanced_usage.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/basic_usage.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/mcp_basic_example.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/mcp_integration.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/parser_demo.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/pin_to_pin_wiring_demo.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/simple_circuit_with_pin_wiring.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/examples/simple_two_resistor_routing.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/cli.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/base.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/components.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/junctions.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/labels.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/collections/wires.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/geometry.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/ic_manager.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/format_sync.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/graphics.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/sheet.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/managers/text_elements.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/core/pin_utils.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/discovery/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/discovery/search_index.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/geometry/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/geometry/font_metrics.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/geometry/symbol_bbox.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/interfaces/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/interfaces/parser.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/interfaces/repository.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/interfaces/resolver.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/library/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/library/cache.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/parsers/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/parsers/base.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/parsers/registry.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/py.typed +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/symbols/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/symbols/cache.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/symbols/resolver.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/symbols/validators.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/utils/__init__.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api/utils/validation.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api.egg-info/dependency_links.txt +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api.egg-info/entry_points.txt +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api.egg-info/requires.txt +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/kicad_sch_api.egg-info/top_level.txt +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/setup.cfg +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/README.md +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/blank_schematic/blank_schematic.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/multi_unit_7400/multi_unit_7400.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/power_symbols/power_symbols.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/resistor_divider/resistor_divider.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/sch_title/sch_title.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_extended_component/single_extended_component.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/single_hierarchical_sheet.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_hierarchical_sheet/subcircuit1.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_label/single_label.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_label_hierarchical/single_label_hierarchical.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_resistor/single_resistor.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_text/single_text.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_text_box/single_text_box.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/single_wire/single_wire.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/two_resistors/two_resistors.kicad_pro +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/reference_tests/reference_kicad_projects/two_resistors/two_resistors.kicad_sch +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_bounding_box_rectangles.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_component_removal.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_element_removal.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_geometry.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_grid_snapping.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_image_support.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_issue_13_public_properties.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_kicad_validation.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_parse_reference_rectangles.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_pin_positioning.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_pin_to_pin_wiring.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_rectangle.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_rectangle_roundtrip.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_removal_against_references.py +0 -0
- {kicad_sch_api-0.4.0 → kicad_sch_api-0.4.2}/tests/test_wire_operations.py +0 -0
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
# PyPI Release Command - kicad-sch-api
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
```bash
|
|
5
|
+
/publish-pypi <version> [--test-only] [--check-only]
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
**⚠️ CRITICAL: Version number is MANDATORY - command will fail if not provided!**
|
|
9
|
+
|
|
10
|
+
## Description
|
|
11
|
+
Complete PyPI release pipeline - from testing to tagging to publishing. This command handles version management, git operations, comprehensive testing, and PyPI publication.
|
|
12
|
+
|
|
13
|
+
## Parameters
|
|
14
|
+
- `version` - **REQUIRED** Version number (e.g., "0.4.1", "1.0.0", "0.5.0-beta.1")
|
|
15
|
+
- `--test-only`: Publish to Test PyPI only (for validation)
|
|
16
|
+
- `--check-only`: Run all checks without publishing
|
|
17
|
+
|
|
18
|
+
## What This Command Does
|
|
19
|
+
|
|
20
|
+
This command automates the complete release process:
|
|
21
|
+
|
|
22
|
+
### 1. Pre-Release Validation
|
|
23
|
+
- **Check branch status** - Ensure we're on main branch
|
|
24
|
+
- **Validate version format** - Semantic versioning check
|
|
25
|
+
- **Check for uncommitted changes** - Ensure clean working directory
|
|
26
|
+
- **Sync with remote** - Fetch latest changes from origin
|
|
27
|
+
- **Version conflict check** - Ensure version doesn't already exist on PyPI or git tags
|
|
28
|
+
|
|
29
|
+
### 2. Version Management
|
|
30
|
+
- **Update pyproject.toml** - Set new version number
|
|
31
|
+
- **Commit version changes** - Clean commit for version bump
|
|
32
|
+
- **Show version comparison** - Display current vs new version
|
|
33
|
+
|
|
34
|
+
### 3. Testing and Validation
|
|
35
|
+
- **Run full test suite** - All tests must pass
|
|
36
|
+
- **Code quality checks** - Black, isort, mypy, flake8
|
|
37
|
+
- **Format preservation tests** - Critical for KiCAD compatibility
|
|
38
|
+
- **Build package** - Create wheel and sdist
|
|
39
|
+
- **Test installation** - Verify package installs correctly
|
|
40
|
+
- **Import validation** - Ensure package imports work
|
|
41
|
+
|
|
42
|
+
### 4. Git Operations
|
|
43
|
+
- **Create release tag** - Tag commit with version number
|
|
44
|
+
- **Push release tag** - Push tag to origin
|
|
45
|
+
- **Create GitHub release** - Generate release notes and publish
|
|
46
|
+
|
|
47
|
+
### 5. PyPI Publication
|
|
48
|
+
- **Build distributions** - Create wheel and sdist
|
|
49
|
+
- **Upload to PyPI** - Publish to registry
|
|
50
|
+
- **Verify upload** - Check package is available
|
|
51
|
+
|
|
52
|
+
### 6. Post-Release Verification
|
|
53
|
+
- **Test installation from PyPI** - Verify package works
|
|
54
|
+
- **Display release summary** - Show URLs and next steps
|
|
55
|
+
|
|
56
|
+
## Implementation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
#!/bin/bash
|
|
60
|
+
set -e # Exit on error
|
|
61
|
+
|
|
62
|
+
# CRITICAL: Always require version number as parameter
|
|
63
|
+
if [ -z "$1" ]; then
|
|
64
|
+
echo "❌ ERROR: Version number is required!"
|
|
65
|
+
echo "Usage: /publish-pypi <version> [--test-only] [--check-only]"
|
|
66
|
+
echo "Example: /publish-pypi 0.4.1"
|
|
67
|
+
echo "Example: /publish-pypi 0.5.0"
|
|
68
|
+
echo "Example: /publish-pypi 1.0.0-beta.1"
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
version="$1"
|
|
73
|
+
shift # Remove version from arguments
|
|
74
|
+
|
|
75
|
+
# Parse flags
|
|
76
|
+
TEST_ONLY=false
|
|
77
|
+
CHECK_ONLY=false
|
|
78
|
+
|
|
79
|
+
while [[ $# -gt 0 ]]; do
|
|
80
|
+
case $1 in
|
|
81
|
+
--test-only)
|
|
82
|
+
TEST_ONLY=true
|
|
83
|
+
shift
|
|
84
|
+
;;
|
|
85
|
+
--check-only)
|
|
86
|
+
CHECK_ONLY=true
|
|
87
|
+
shift
|
|
88
|
+
;;
|
|
89
|
+
*)
|
|
90
|
+
echo "Unknown option: $1"
|
|
91
|
+
exit 1
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
94
|
+
done
|
|
95
|
+
|
|
96
|
+
echo "🎯 Starting release process for kicad-sch-api version: $version"
|
|
97
|
+
echo "================================================================"
|
|
98
|
+
|
|
99
|
+
# 1. Pre-flight checks and branch management
|
|
100
|
+
echo "🔍 Running pre-flight checks..."
|
|
101
|
+
|
|
102
|
+
# Fetch latest changes from remote
|
|
103
|
+
echo "🔄 Fetching latest changes from origin..."
|
|
104
|
+
git fetch origin
|
|
105
|
+
|
|
106
|
+
# Ensure clean working directory
|
|
107
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
108
|
+
echo "❌ Uncommitted changes found. Commit or stash first."
|
|
109
|
+
exit 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Check current branch
|
|
113
|
+
current_branch=$(git branch --show-current)
|
|
114
|
+
if [[ "$current_branch" != "main" ]]; then
|
|
115
|
+
echo "⚠️ Warning: Not on main branch (currently on '$current_branch')"
|
|
116
|
+
read -p "Continue? (y/N): " -n 1 -r
|
|
117
|
+
echo ""
|
|
118
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Validate version format (semantic versioning)
|
|
124
|
+
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
|
|
125
|
+
echo "❌ Invalid version format. Use semantic versioning (e.g., 0.4.1, 1.0.0)"
|
|
126
|
+
echo "Provided: $version"
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Show current version for comparison
|
|
131
|
+
current_version=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
|
|
132
|
+
echo "📊 Current version: $current_version"
|
|
133
|
+
echo "📊 New version: $version"
|
|
134
|
+
echo ""
|
|
135
|
+
read -p "🤔 Confirm release version $version? (y/N): " -n 1 -r
|
|
136
|
+
echo ""
|
|
137
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
138
|
+
echo "❌ Release cancelled. Please specify the correct version."
|
|
139
|
+
exit 1
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# Check if version already exists on PyPI
|
|
143
|
+
echo "🔍 Checking if version already exists on PyPI..."
|
|
144
|
+
if pip index versions kicad-sch-api 2>/dev/null | grep -q "kicad-sch-api ($version)"; then
|
|
145
|
+
echo "❌ Version $version already exists on PyPI"
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Check if git tag already exists
|
|
150
|
+
if git rev-parse "v$version" >/dev/null 2>&1; then
|
|
151
|
+
echo "❌ Git tag v$version already exists"
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Ensure main is up-to-date with origin
|
|
156
|
+
echo "🔄 Ensuring main is up-to-date..."
|
|
157
|
+
git pull origin main || {
|
|
158
|
+
echo "❌ Failed to pull latest main"
|
|
159
|
+
exit 1
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Install build dependencies
|
|
163
|
+
echo "📥 Installing build dependencies..."
|
|
164
|
+
uv pip install build twine --quiet
|
|
165
|
+
|
|
166
|
+
# 2. Version update
|
|
167
|
+
echo "📝 Updating version to $version..."
|
|
168
|
+
|
|
169
|
+
# Update pyproject.toml
|
|
170
|
+
sed -i.bak "s/^version = .*/version = \"$version\"/" pyproject.toml
|
|
171
|
+
rm -f pyproject.toml.bak
|
|
172
|
+
|
|
173
|
+
# Check if changes were made
|
|
174
|
+
if ! git diff --quiet pyproject.toml; then
|
|
175
|
+
git add pyproject.toml
|
|
176
|
+
git commit -m "🔖 Bump version to $version"
|
|
177
|
+
echo "✅ Version updated and committed"
|
|
178
|
+
else
|
|
179
|
+
echo "ℹ️ Version already up to date"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# 3. Code quality checks
|
|
183
|
+
echo "🎨 Checking code quality..."
|
|
184
|
+
|
|
185
|
+
# Format check
|
|
186
|
+
echo " - Checking code formatting..."
|
|
187
|
+
if ! uv run black --check kicad_sch_api/ tests/ --quiet 2>/dev/null; then
|
|
188
|
+
echo "❌ Code not formatted. Run: uv run black kicad_sch_api/ tests/"
|
|
189
|
+
exit 1
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
# Import sort check
|
|
193
|
+
echo " - Checking import sorting..."
|
|
194
|
+
if ! uv run isort --check-only kicad_sch_api/ tests/ --quiet 2>/dev/null; then
|
|
195
|
+
echo "❌ Imports not sorted. Run: uv run isort kicad_sch_api/ tests/"
|
|
196
|
+
exit 1
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Type checking
|
|
200
|
+
echo " - Running type checks..."
|
|
201
|
+
uv run mypy kicad_sch_api/ --ignore-missing-imports --quiet 2>/dev/null || {
|
|
202
|
+
echo "⚠️ Type checking issues found (non-blocking)"
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
echo "✅ Code quality checks passed"
|
|
206
|
+
|
|
207
|
+
# 4. Comprehensive testing
|
|
208
|
+
echo "🧪 Running comprehensive test suite..."
|
|
209
|
+
|
|
210
|
+
# Core tests - format preservation is critical for KiCAD compatibility
|
|
211
|
+
echo " - Running unit tests..."
|
|
212
|
+
if ! uv run pytest tests/ -v --tb=short -q; then
|
|
213
|
+
echo "❌ Tests failed"
|
|
214
|
+
exit 1
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# Format preservation tests (CRITICAL for KiCAD compatibility)
|
|
218
|
+
echo " - Running format preservation tests..."
|
|
219
|
+
if ! uv run pytest tests/reference_tests/ -v --tb=short -q 2>/dev/null; then
|
|
220
|
+
echo "⚠️ Format preservation tests not found or failed"
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
# Import validation
|
|
224
|
+
echo " - Testing imports..."
|
|
225
|
+
if ! uv run python -c "import kicad_sch_api; print('✅ Import successful')" 2>/dev/null; then
|
|
226
|
+
echo "❌ Import test failed"
|
|
227
|
+
exit 1
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
echo "✅ All tests passed"
|
|
231
|
+
|
|
232
|
+
# 5. Build package
|
|
233
|
+
echo "🏗️ Building package..."
|
|
234
|
+
|
|
235
|
+
# Clean previous builds
|
|
236
|
+
rm -rf build/ dist/ *.egg-info/ kicad_sch_api.egg-info/
|
|
237
|
+
|
|
238
|
+
# Build
|
|
239
|
+
if ! python -m build; then
|
|
240
|
+
echo "❌ Package build failed"
|
|
241
|
+
exit 1
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
echo "✅ Package built successfully"
|
|
245
|
+
|
|
246
|
+
# 6. Package validation
|
|
247
|
+
echo "📋 Validating package..."
|
|
248
|
+
|
|
249
|
+
# Check package integrity
|
|
250
|
+
if ! twine check dist/*; then
|
|
251
|
+
echo "❌ Package validation failed"
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# Test installation in clean environment
|
|
256
|
+
echo "🧪 Testing package installation in isolated environment..."
|
|
257
|
+
TEMP_VENV=$(mktemp -d)
|
|
258
|
+
python -m venv "$TEMP_VENV"
|
|
259
|
+
source "$TEMP_VENV/bin/activate"
|
|
260
|
+
|
|
261
|
+
if ! pip install dist/*.whl --quiet; then
|
|
262
|
+
echo "❌ Package installation failed"
|
|
263
|
+
deactivate
|
|
264
|
+
rm -rf "$TEMP_VENV"
|
|
265
|
+
exit 1
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
if ! python -c "import kicad_sch_api; print('✅ Package import successful')"; then
|
|
269
|
+
echo "❌ Package import failed"
|
|
270
|
+
deactivate
|
|
271
|
+
rm -rf "$TEMP_VENV"
|
|
272
|
+
exit 1
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
deactivate
|
|
276
|
+
rm -rf "$TEMP_VENV"
|
|
277
|
+
|
|
278
|
+
echo "✅ Package validation complete"
|
|
279
|
+
|
|
280
|
+
# 7. Exit if check-only
|
|
281
|
+
if [[ "$CHECK_ONLY" == "true" ]]; then
|
|
282
|
+
echo ""
|
|
283
|
+
echo "================================================"
|
|
284
|
+
echo "✅ All pre-publication checks passed"
|
|
285
|
+
echo "================================================"
|
|
286
|
+
echo "📦 Package ready for publication"
|
|
287
|
+
echo "📊 Version: $version"
|
|
288
|
+
echo "🏷️ Next step: Run without --check-only to publish"
|
|
289
|
+
exit 0
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
# 8. Git tagging and GitHub release
|
|
293
|
+
echo "🏷️ Creating git tag and GitHub release..."
|
|
294
|
+
|
|
295
|
+
# Verify we're on main branch for tagging
|
|
296
|
+
current_branch_for_tag=$(git branch --show-current)
|
|
297
|
+
if [[ "$current_branch_for_tag" != "main" ]]; then
|
|
298
|
+
echo "❌ Must be on main branch for release tagging"
|
|
299
|
+
echo "💡 Switch to main branch and re-run this command"
|
|
300
|
+
exit 1
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
# Generate release notes from commits since last tag
|
|
304
|
+
last_tag=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
|
|
305
|
+
if [ -n "$last_tag" ]; then
|
|
306
|
+
echo "📋 Generating release notes since $last_tag..."
|
|
307
|
+
release_notes=$(git log --pretty=format:"- %s (%h)" "$last_tag"..HEAD)
|
|
308
|
+
else
|
|
309
|
+
echo "📋 Generating release notes for initial release..."
|
|
310
|
+
release_notes=$(git log --pretty=format:"- %s (%h)" --max-count=10)
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
# Create git tag
|
|
314
|
+
echo "🏷️ Creating git tag v$version..."
|
|
315
|
+
git tag -a "v$version" -m "🚀 Release version $version
|
|
316
|
+
|
|
317
|
+
Features and changes in this release:
|
|
318
|
+
$release_notes
|
|
319
|
+
|
|
320
|
+
Full changelog: https://github.com/circuit-synth/kicad-sch-api/compare/${last_tag}...v$version"
|
|
321
|
+
|
|
322
|
+
# Push tag to origin
|
|
323
|
+
echo "📤 Pushing release tag to origin..."
|
|
324
|
+
git push origin "v$version" || {
|
|
325
|
+
echo "❌ Failed to push release tag"
|
|
326
|
+
exit 1
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
echo "✅ Tagged and pushed v$version"
|
|
330
|
+
|
|
331
|
+
# Create GitHub release using gh CLI
|
|
332
|
+
if command -v gh >/dev/null 2>&1; then
|
|
333
|
+
echo "📝 Creating GitHub release..."
|
|
334
|
+
|
|
335
|
+
gh release create "v$version" \
|
|
336
|
+
--title "🚀 Release v$version" \
|
|
337
|
+
--notes "## What's Changed
|
|
338
|
+
|
|
339
|
+
$release_notes
|
|
340
|
+
|
|
341
|
+
## Installation
|
|
342
|
+
|
|
343
|
+
\`\`\`bash
|
|
344
|
+
pip install kicad-sch-api==$version
|
|
345
|
+
# or
|
|
346
|
+
uv add kicad-sch-api==$version
|
|
347
|
+
\`\`\`
|
|
348
|
+
|
|
349
|
+
## PyPI Package
|
|
350
|
+
📦 https://pypi.org/project/kicad-sch-api/$version/
|
|
351
|
+
|
|
352
|
+
**Full Changelog**: https://github.com/circuit-synth/kicad-sch-api/compare/${last_tag}...v$version" \
|
|
353
|
+
--latest || {
|
|
354
|
+
echo "⚠️ GitHub release creation failed (continuing with PyPI release)"
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
echo "✅ GitHub release created"
|
|
358
|
+
else
|
|
359
|
+
echo "⚠️ GitHub CLI (gh) not found - skipping GitHub release creation"
|
|
360
|
+
echo "💡 Install with: brew install gh"
|
|
361
|
+
echo "📝 Manual release notes:"
|
|
362
|
+
echo "$release_notes"
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
# 9. Publish to PyPI
|
|
366
|
+
echo ""
|
|
367
|
+
echo "🚀 Publishing to PyPI..."
|
|
368
|
+
|
|
369
|
+
if [[ "$TEST_ONLY" == "true" ]]; then
|
|
370
|
+
# Publish to Test PyPI
|
|
371
|
+
echo "📡 Publishing to Test PyPI..."
|
|
372
|
+
|
|
373
|
+
# Use environment variable or .pypirc
|
|
374
|
+
if [[ -n "$TEST_PYPI_API_TOKEN" ]]; then
|
|
375
|
+
twine upload --repository testpypi dist/* --username __token__ --password "$TEST_PYPI_API_TOKEN"
|
|
376
|
+
else
|
|
377
|
+
echo "ℹ️ Using .pypirc credentials for Test PyPI..."
|
|
378
|
+
twine upload --repository testpypi dist/*
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
if [[ $? -eq 0 ]]; then
|
|
382
|
+
echo "✅ Successfully published to Test PyPI"
|
|
383
|
+
echo "🔗 View at: https://test.pypi.org/project/kicad-sch-api/"
|
|
384
|
+
echo "📥 Test install: pip install --index-url https://test.pypi.org/simple/ kicad-sch-api"
|
|
385
|
+
else
|
|
386
|
+
echo "❌ Test PyPI publication failed"
|
|
387
|
+
exit 1
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
else
|
|
391
|
+
# Publish to production PyPI
|
|
392
|
+
echo "📡 Publishing to Production PyPI..."
|
|
393
|
+
|
|
394
|
+
# Final confirmation
|
|
395
|
+
echo ""
|
|
396
|
+
echo "⚠️ WARNING: Publishing to PRODUCTION PyPI"
|
|
397
|
+
echo "This action cannot be undone for this version."
|
|
398
|
+
echo "Version: $version"
|
|
399
|
+
read -p "Continue? (y/N): " -n 1 -r confirm
|
|
400
|
+
echo ""
|
|
401
|
+
|
|
402
|
+
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
|
|
403
|
+
echo "❌ Publication cancelled"
|
|
404
|
+
# Clean up git tag since we're not publishing
|
|
405
|
+
git tag -d "v$version" 2>/dev/null
|
|
406
|
+
git push origin ":refs/tags/v$version" 2>/dev/null
|
|
407
|
+
exit 1
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
# Use environment variable or .pypirc
|
|
411
|
+
if [[ -n "$PYPI_API_TOKEN" ]]; then
|
|
412
|
+
twine upload dist/* --username __token__ --password "$PYPI_API_TOKEN"
|
|
413
|
+
else
|
|
414
|
+
echo "ℹ️ Using .pypirc credentials for PyPI..."
|
|
415
|
+
twine upload dist/*
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
if [[ $? -eq 0 ]]; then
|
|
419
|
+
echo ""
|
|
420
|
+
echo "🎉 Successfully published to PyPI!"
|
|
421
|
+
echo "🔗 View at: https://pypi.org/project/kicad-sch-api/$version/"
|
|
422
|
+
echo "📥 Install: pip install kicad-sch-api==$version"
|
|
423
|
+
else
|
|
424
|
+
echo "❌ PyPI publication failed"
|
|
425
|
+
exit 1
|
|
426
|
+
fi
|
|
427
|
+
fi
|
|
428
|
+
|
|
429
|
+
# 10. Post-release verification
|
|
430
|
+
echo ""
|
|
431
|
+
echo "⏳ Waiting for PyPI propagation (30 seconds)..."
|
|
432
|
+
sleep 30
|
|
433
|
+
|
|
434
|
+
# Verify package is available on PyPI
|
|
435
|
+
echo "🔍 Verifying package on PyPI..."
|
|
436
|
+
package_info=$(pip index versions kicad-sch-api 2>/dev/null || echo "not found")
|
|
437
|
+
if [[ "$package_info" == *"$version"* ]]; then
|
|
438
|
+
echo "✅ Package verified on PyPI"
|
|
439
|
+
else
|
|
440
|
+
echo "⚠️ Package not yet visible on PyPI (may take a few minutes)"
|
|
441
|
+
fi
|
|
442
|
+
|
|
443
|
+
# Test installation from PyPI in clean environment (production only)
|
|
444
|
+
if [[ "$TEST_ONLY" == "false" ]]; then
|
|
445
|
+
echo "🧪 Testing installation from PyPI..."
|
|
446
|
+
temp_dir=$(mktemp -d)
|
|
447
|
+
cd "$temp_dir"
|
|
448
|
+
python -m venv test_env
|
|
449
|
+
source test_env/bin/activate
|
|
450
|
+
|
|
451
|
+
pip install kicad-sch-api==$version --quiet && \
|
|
452
|
+
python -c "import kicad_sch_api; print(f'✅ Installed version: {kicad_sch_api.__version__ if hasattr(kicad_sch_api, \"__version__\") else \"unknown\"}')" || \
|
|
453
|
+
echo "⚠️ Installation test from PyPI failed (package may still be propagating)"
|
|
454
|
+
|
|
455
|
+
deactivate
|
|
456
|
+
cd - >/dev/null
|
|
457
|
+
rm -rf "$temp_dir"
|
|
458
|
+
fi
|
|
459
|
+
|
|
460
|
+
# Final summary
|
|
461
|
+
echo ""
|
|
462
|
+
echo "================================================================"
|
|
463
|
+
echo "🎉 Release v$version Complete!"
|
|
464
|
+
echo "================================================================"
|
|
465
|
+
echo "📊 Release Summary:"
|
|
466
|
+
echo " 📦 PyPI: https://pypi.org/project/kicad-sch-api/$version/"
|
|
467
|
+
echo " 🏷️ Git Tag: v$version"
|
|
468
|
+
echo " 📋 GitHub: https://github.com/circuit-synth/kicad-sch-api/releases/tag/v$version"
|
|
469
|
+
echo ""
|
|
470
|
+
echo "✅ Publication process completed successfully"
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Usage Examples
|
|
474
|
+
|
|
475
|
+
### Recommended Workflow
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
# 1. First, check that everything is ready (dry run)
|
|
479
|
+
/publish-pypi 0.4.1 --check-only
|
|
480
|
+
|
|
481
|
+
# 2. Test on Test PyPI first (HIGHLY RECOMMENDED)
|
|
482
|
+
/publish-pypi 0.4.1 --test-only
|
|
483
|
+
|
|
484
|
+
# 3. Verify Test PyPI installation works
|
|
485
|
+
pip install --index-url https://test.pypi.org/simple/ kicad-sch-api==0.4.1
|
|
486
|
+
|
|
487
|
+
# 4. If everything looks good, publish to production PyPI
|
|
488
|
+
/publish-pypi 0.4.1
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Other Examples
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
# Release a patch version
|
|
495
|
+
/publish-pypi 0.4.1
|
|
496
|
+
|
|
497
|
+
# Release a minor version
|
|
498
|
+
/publish-pypi 0.5.0
|
|
499
|
+
|
|
500
|
+
# Release a major version
|
|
501
|
+
/publish-pypi 1.0.0
|
|
502
|
+
|
|
503
|
+
# Release a beta version
|
|
504
|
+
/publish-pypi 1.0.0-beta.1
|
|
505
|
+
|
|
506
|
+
# Release a release candidate
|
|
507
|
+
/publish-pypi 1.0.0-rc.1
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Authentication Methods
|
|
511
|
+
|
|
512
|
+
### Method 1: Environment Variables (Recommended for CI)
|
|
513
|
+
|
|
514
|
+
#### For Test PyPI
|
|
515
|
+
```bash
|
|
516
|
+
export TEST_PYPI_API_TOKEN=pypi-your_test_token_here
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### For Production PyPI
|
|
520
|
+
```bash
|
|
521
|
+
export PYPI_API_TOKEN=pypi-your_production_token_here
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Method 2: .pypirc File (Recommended for Local Development)
|
|
525
|
+
|
|
526
|
+
Create `~/.pypirc` with your API tokens:
|
|
527
|
+
|
|
528
|
+
```ini
|
|
529
|
+
[distutils]
|
|
530
|
+
index-servers =
|
|
531
|
+
pypi
|
|
532
|
+
testpypi
|
|
533
|
+
|
|
534
|
+
[pypi]
|
|
535
|
+
repository = https://upload.pypi.org/legacy/
|
|
536
|
+
username = __token__
|
|
537
|
+
password = pypi-your_production_token_here
|
|
538
|
+
|
|
539
|
+
[testpypi]
|
|
540
|
+
repository = https://test.pypi.org/legacy/
|
|
541
|
+
username = __token__
|
|
542
|
+
password = pypi-your_test_token_here
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Using .pypirc:**
|
|
546
|
+
```bash
|
|
547
|
+
# Publish to Test PyPI using .pypirc
|
|
548
|
+
twine upload --repository testpypi dist/*
|
|
549
|
+
|
|
550
|
+
# Publish to Production PyPI using .pypirc
|
|
551
|
+
twine upload --repository pypi dist/*
|
|
552
|
+
|
|
553
|
+
# Or use the default (production PyPI)
|
|
554
|
+
twine upload dist/*
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Security Notes:**
|
|
558
|
+
- Set proper file permissions: `chmod 600 ~/.pypirc`
|
|
559
|
+
- Never commit `.pypirc` to version control
|
|
560
|
+
- Environment variables take precedence over `.pypirc`
|
|
561
|
+
- Use scoped API tokens (project-specific) instead of global tokens
|
|
562
|
+
|
|
563
|
+
## Prerequisites
|
|
564
|
+
|
|
565
|
+
Before running this command, ensure you have:
|
|
566
|
+
|
|
567
|
+
1. **PyPI account** with API token configured
|
|
568
|
+
2. **Git credentials** set up for pushing
|
|
569
|
+
3. **GitHub CLI (gh)** installed and authenticated (for GitHub releases)
|
|
570
|
+
4. **Clean working directory** (no uncommitted changes)
|
|
571
|
+
5. **Main branch** checked out (for production releases)
|
|
572
|
+
|
|
573
|
+
### Setup GitHub CLI
|
|
574
|
+
```bash
|
|
575
|
+
# Install GitHub CLI
|
|
576
|
+
brew install gh
|
|
577
|
+
|
|
578
|
+
# Authenticate with GitHub
|
|
579
|
+
gh auth login
|
|
580
|
+
|
|
581
|
+
# Verify authentication
|
|
582
|
+
gh auth status
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
## Version Numbering Strategy
|
|
586
|
+
|
|
587
|
+
This project follows **Semantic Versioning** (semver.org):
|
|
588
|
+
|
|
589
|
+
- **MAJOR.MINOR.PATCH** (e.g., 0.4.1)
|
|
590
|
+
- **MAJOR**: Breaking API changes
|
|
591
|
+
- **MINOR**: New features, backward compatible
|
|
592
|
+
- **PATCH**: Bug fixes, backward compatible
|
|
593
|
+
|
|
594
|
+
**For pre-1.0 versions (0.x.y):**
|
|
595
|
+
- Minor version bumps may include breaking changes
|
|
596
|
+
- Communicate clearly in release notes
|
|
597
|
+
- Move to v1.0.0 when API is stable
|
|
598
|
+
|
|
599
|
+
**Examples:**
|
|
600
|
+
- `0.4.0 → 0.4.1` - Bug fixes, small improvements
|
|
601
|
+
- `0.4.1 → 0.5.0` - New features (bus support, netlist generation)
|
|
602
|
+
- `0.5.0 → 1.0.0` - API stable, production ready
|
|
603
|
+
|
|
604
|
+
## What Gets Released
|
|
605
|
+
|
|
606
|
+
The release process creates:
|
|
607
|
+
- **Python package** - Wheel and source distribution on PyPI
|
|
608
|
+
- **Git tag** - Version tag on main branch (e.g., `v0.4.1`)
|
|
609
|
+
- **GitHub release** - Auto-generated release notes
|
|
610
|
+
- **Documentation** - All examples and docs included in package
|
|
611
|
+
|
|
612
|
+
## Safety Features
|
|
613
|
+
|
|
614
|
+
This enhanced command includes:
|
|
615
|
+
|
|
616
|
+
✅ **Mandatory version parameter** - Prevents accidental releases
|
|
617
|
+
✅ **Version conflict detection** - Checks PyPI and git tags
|
|
618
|
+
✅ **Semantic versioning validation** - Ensures proper version format
|
|
619
|
+
✅ **Clean working directory check** - No uncommitted changes
|
|
620
|
+
✅ **Main branch enforcement** - Production releases only from main
|
|
621
|
+
✅ **Comprehensive testing** - Unit tests, format preservation, imports
|
|
622
|
+
✅ **Package validation** - Twine checks, installation tests
|
|
623
|
+
✅ **Automatic git tagging** - Creates and pushes version tags
|
|
624
|
+
✅ **GitHub release creation** - Auto-generated release notes
|
|
625
|
+
✅ **Post-release verification** - Tests installation from PyPI
|
|
626
|
+
|
|
627
|
+
## Troubleshooting
|
|
628
|
+
|
|
629
|
+
### Common Issues
|
|
630
|
+
|
|
631
|
+
**Version already exists:**
|
|
632
|
+
```bash
|
|
633
|
+
❌ Version 0.4.1 already exists on PyPI
|
|
634
|
+
# Solution: Increment version number (you cannot overwrite PyPI versions)
|
|
635
|
+
/publish-pypi 0.4.2
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Git tag already exists:**
|
|
639
|
+
```bash
|
|
640
|
+
❌ Git tag v0.4.1 already exists
|
|
641
|
+
# Solution: Delete tag or use new version
|
|
642
|
+
git tag -d v0.4.1 # Delete local tag
|
|
643
|
+
git push origin :refs/tags/v0.4.1 # Delete remote tag
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
**Not on main branch:**
|
|
647
|
+
```bash
|
|
648
|
+
⚠️ Warning: Not on main branch (currently on 'develop')
|
|
649
|
+
# Solution: Switch to main or force continue
|
|
650
|
+
git checkout main
|
|
651
|
+
git pull origin main
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
**Tests failing:**
|
|
655
|
+
```bash
|
|
656
|
+
❌ Tests failed
|
|
657
|
+
# Solution: Fix failing tests before publishing
|
|
658
|
+
uv run pytest tests/ -v
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
**GitHub CLI not found:**
|
|
662
|
+
```bash
|
|
663
|
+
⚠️ GitHub CLI (gh) not found - skipping GitHub release creation
|
|
664
|
+
# Solution: Install gh (optional, not required for PyPI)
|
|
665
|
+
brew install gh
|
|
666
|
+
gh auth login
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Rollback Procedure
|
|
670
|
+
|
|
671
|
+
If something goes wrong after publishing:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
# 1. Yank the bad release from PyPI (prevents new installations)
|
|
675
|
+
pip install twine
|
|
676
|
+
twine yank kicad-sch-api --version BAD_VERSION
|
|
677
|
+
|
|
678
|
+
# 2. Delete the git tag (optional)
|
|
679
|
+
git tag -d vBAD_VERSION
|
|
680
|
+
git push origin :refs/tags/vBAD_VERSION
|
|
681
|
+
|
|
682
|
+
# 3. Delete the GitHub release (optional)
|
|
683
|
+
gh release delete vBAD_VERSION
|
|
684
|
+
|
|
685
|
+
# 4. Fix the issues and release a new patch version
|
|
686
|
+
/publish-pypi NEW_VERSION
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
## Comparison with Previous Version
|
|
690
|
+
|
|
691
|
+
### Old Command (Issue #2-4)
|
|
692
|
+
❌ No version parameter
|
|
693
|
+
❌ No git tagging
|
|
694
|
+
❌ No GitHub releases
|
|
695
|
+
❌ No version conflict detection
|
|
696
|
+
❌ Manual version management
|
|
697
|
+
|
|
698
|
+
### Enhanced Command (This Version)
|
|
699
|
+
✅ Mandatory version parameter
|
|
700
|
+
✅ Automatic git tagging
|
|
701
|
+
✅ GitHub release creation
|
|
702
|
+
✅ Version conflict detection
|
|
703
|
+
✅ Automatic version updates
|
|
704
|
+
✅ Comprehensive validation
|
|
705
|
+
✅ Post-release verification
|
|
706
|
+
|
|
707
|
+
This addresses **GitHub Issues #2, #3, and #4** by preventing version confusion and ensuring proper release workflow.
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
**This command provides a complete, automated PyPI release pipeline with comprehensive validation and safety checks, ensuring every release is properly tagged, tested, and documented.**
|