codeplain 0.3.8__tar.gz → 0.3.10.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.github/workflows/e2e.yml +28 -1
  2. codeplain-0.3.10.dev1/.github/workflows/lint-powershell.yml +124 -0
  3. codeplain-0.3.10.dev1/.github/workflows/publish-dev-to-pypi.yml +135 -0
  4. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.github/workflows/publish-install-script.yml +17 -0
  5. codeplain-0.3.10.dev1/.github/workflows/publish-to-pypi.yml +117 -0
  6. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/CLAUDE.md +10 -6
  7. codeplain-0.3.10.dev1/CONTRIBUTING.md +137 -0
  8. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/PKG-INFO +36 -8
  9. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/README.md +31 -3
  10. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/concept_utils.py +6 -0
  11. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/docs/plain2code_cli.md +25 -23
  12. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/docs/starting_a_plain_project_from_scratch.md +8 -2
  13. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_golang/run.sh +2 -2
  14. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_python/run.sh +2 -2
  15. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/run.sh +1 -1
  16. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/git_utils.py +0 -10
  17. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/install/bash/install.sh +41 -0
  18. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/install/powershell/examples.ps1 +11 -5
  19. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/install/powershell/install.ps1 +131 -19
  20. codeplain-0.3.10.dev1/install/powershell/walkthrough.ps1 +174 -0
  21. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/memory_management.py +2 -3
  22. codeplain-0.3.10.dev1/metadata_utils.py +46 -0
  23. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/module_renderer.py +9 -6
  24. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/partial_rendering.py +35 -4
  25. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code.py +37 -4
  26. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_arguments.py +13 -19
  27. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_cli.md +17 -19
  28. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_console.py +3 -1
  29. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_exceptions.py +8 -0
  30. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_logger.py +37 -15
  31. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_telemetry.py +17 -11
  32. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain_file.py +18 -1
  33. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain_modules.py +264 -42
  34. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/pyproject.toml +3 -3
  35. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/prepare_repositories.py +8 -10
  36. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/conformance_tests.py +48 -9
  37. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/implementation_code_helpers.py +5 -1
  38. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/render_context.py +14 -4
  39. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/render_utils.py +1 -2
  40. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/requirements.txt +3 -3
  41. codeplain-0.3.10.dev1/system_config.py +148 -0
  42. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/e2e/test_hello_world_python.py +1 -1
  43. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/e2e/test_hello_world_python_windows.py +1 -1
  44. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_arg_provenance.py +3 -3
  45. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_cli_output.py +13 -0
  46. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_folder_path_resolution.py +12 -13
  47. codeplain-0.3.10.dev1/tests/test_headless_logging.py +177 -0
  48. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plain2code.py +1 -2
  49. codeplain-0.3.10.dev1/tests/test_plain_modules.py +794 -0
  50. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plainfileparser.py +41 -4
  51. codeplain-0.3.10.dev1/tests/test_prepare_repositories_layout.py +277 -0
  52. codeplain-0.3.10.dev1/tests/test_system_config.py +95 -0
  53. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_telemetry.py +31 -10
  54. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/plain_module_render_choice_tui.py +25 -8
  55. codeplain-0.3.8/.github/workflows/publish-to-pypi.yml +0 -70
  56. codeplain-0.3.8/install/powershell/walkthrough.ps1 +0 -161
  57. codeplain-0.3.8/system_config.py +0 -68
  58. codeplain-0.3.8/tests/test_plain_modules.py +0 -343
  59. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.claude/settings.json +0 -0
  60. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.flake8 +0 -0
  61. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.github/dependabot.yml +0 -0
  62. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.github/workflows/lint-and-test.yml +0 -0
  63. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.github/workflows/nofity-slack-on-main-merge.yml +0 -0
  64. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.gitignore +0 -0
  65. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.vscode/launch.json +0 -0
  66. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/.vscode/settings.json +0 -0
  67. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/LICENSE +0 -0
  68. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/change_detection.py +0 -0
  69. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/cli_output/__init__.py +0 -0
  70. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/cli_output/dry_run.py +0 -0
  71. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/cli_output/render_summary.py +0 -0
  72. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/cli_output/status.py +0 -0
  73. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/codeplain_REST_api.py +0 -0
  74. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/config/__init__.py +0 -0
  75. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/config/system_config.yaml +0 -0
  76. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/diff_utils.py +0 -0
  77. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/docs/generate_cli.py +0 -0
  78. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/event_bus.py +0 -0
  79. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_golang/config.yaml +0 -0
  80. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  81. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  82. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_python/config.yaml +0 -0
  83. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  84. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  85. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/config.yaml +0 -0
  86. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  87. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  88. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  89. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  90. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  91. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  92. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/examples/run.sh +0 -0
  93. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/file_utils.py +0 -0
  94. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/install/bash/examples.sh +0 -0
  95. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/install/bash/walkthrough.sh +0 -0
  96. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/path_resolution.py +0 -0
  97. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_events.py +0 -0
  98. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_nodes.py +0 -0
  99. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_read_config.py +0 -0
  100. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_state.py +0 -0
  101. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain2code_utils.py +0 -0
  102. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/plain_spec.py +0 -0
  103. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/pytest.ini +0 -0
  104. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/__init__.py +0 -0
  105. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  106. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/base_action.py +0 -0
  107. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  108. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  109. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/create_dist.py +0 -0
  110. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/exit_with_error.py +0 -0
  111. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/finish_functional_requirement.py +0 -0
  112. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/fix_conformance_test.py +0 -0
  113. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/fix_unit_tests.py +0 -0
  114. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/prepare_testing_environment.py +0 -0
  115. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/refactor_code.py +0 -0
  116. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/render_conformance_tests.py +0 -0
  117. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/render_functional_requirement.py +0 -0
  118. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/run_conformance_tests.py +0 -0
  119. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/run_unit_tests.py +0 -0
  120. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/actions/summarize_conformance_tests.py +0 -0
  121. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/code_renderer.py +0 -0
  122. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/render_types.py +0 -0
  123. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/state_machine_config.py +0 -0
  124. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/states.py +0 -0
  125. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/render_machine/triggers.py +0 -0
  126. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/resources/codeplain_overview.png +0 -0
  127. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/resources/plain_example.png +0 -0
  128. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/standard_template_library/golang-console-app-template.plain +0 -0
  129. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/standard_template_library/python-console-app-template.plain +0 -0
  130. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  131. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/standard_template_library/typescript-react-app-template.plain +0 -0
  132. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  133. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  134. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  135. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_golang.sh +0 -0
  136. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  137. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_conformance_tests_python.sh +0 -0
  138. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_flutter.ps1 +0 -0
  139. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_flutter.sh +0 -0
  140. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_golang.ps1 +0 -0
  141. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_golang.sh +0 -0
  142. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_python.ps1 +0 -0
  143. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_python.sh +0 -0
  144. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_react.ps1 +0 -0
  145. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/test_scripts/run_unittests_react.sh +0 -0
  146. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/__init__.py +0 -0
  147. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/conftest.py +0 -0
  148. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
  149. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
  150. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/circular_imports_1.plain +0 -0
  151. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/circular_imports_2.plain +0 -0
  152. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/circular_imports_main.plain +0 -0
  153. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/diamond_import_1.plain +0 -0
  154. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/diamond_import_2.plain +0 -0
  155. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/diamond_import_common.plain +0 -0
  156. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/diamond_imports_main.plain +0 -0
  157. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/import_with_functionalities.plain +0 -0
  158. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
  159. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/imports/non_existent_import.plain +0 -0
  160. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_code_var.plain +0 -0
  161. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_implement.plain +0 -0
  162. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  163. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_middle.plain +0 -0
  164. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_root.plain +0 -0
  165. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/partial_rendering/pr_solo.plain +0 -0
  166. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
  167. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  168. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
  169. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  170. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  171. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
  172. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  173. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  174. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
  175. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  176. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  177. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  178. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  179. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  180. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  181. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  182. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  183. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  184. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  185. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  186. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  187. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  188. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  189. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  190. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  191. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  192. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  193. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  194. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  195. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  196. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  197. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  198. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  199. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  200. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  201. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts.plain +0 -0
  202. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  203. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  204. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  205. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  206. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  207. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  208. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  209. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  210. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/topological_sort.plain +0 -0
  211. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  212. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/circular_requires_main.plain +0 -0
  213. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/circular_requires_sub.plain +0 -0
  214. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/diamond_requires_1.plain +0 -0
  215. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/diamond_requires_2.plain +0 -0
  216. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/diamond_requires_common.plain +0 -0
  217. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/diamond_requires_main.plain +0 -0
  218. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/independent_requires_1.plain +0 -0
  219. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/independent_requires_2.plain +0 -0
  220. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/independent_requires_main.plain +0 -0
  221. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/non_existent_require.plain +0 -0
  222. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/normal_requires_1.plain +0 -0
  223. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/normal_requires_2.plain +0 -0
  224. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/normal_requires_common.plain +0 -0
  225. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/requires/normal_requires_main.plain +0 -0
  226. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/sample_base64_image.txt +0 -0
  227. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/simple.plain +0 -0
  228. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/block_level_include.plain +0 -0
  229. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/code_variables.plain +0 -0
  230. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/header.plain +0 -0
  231. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/implement.plain +0 -0
  232. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/implement_2.plain +0 -0
  233. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/template_include.plain +0 -0
  234. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/data/templates/test_hardest_problem.plain +0 -0
  235. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/e2e/Dockerfile +0 -0
  236. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/e2e/conftest.py +0 -0
  237. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_change_detection.py +0 -0
  238. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_console_log_styles.py +0 -0
  239. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_file_utils.py +0 -0
  240. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_git_utils.py +0 -0
  241. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_imports.py +0 -0
  242. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_log_file_name_resolution.py +0 -0
  243. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_logging_config_path_resolution.py +0 -0
  244. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_partial_rendering.py +0 -0
  245. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_path_resolution.py +0 -0
  246. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plain2code_state.py +0 -0
  247. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plain2code_utils.py +0 -0
  248. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plainfile.py +0 -0
  249. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_plainspec.py +0 -0
  250. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_requires.py +0 -0
  251. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_resolve_config_file.py +0 -0
  252. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_script_path_resolution.py +0 -0
  253. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_tui_usage.py +0 -0
  254. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tests/test_usage_summary.py +0 -0
  255. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/__init__.py +0 -0
  256. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/components.py +0 -0
  257. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/models.py +0 -0
  258. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/plain2code_tui.py +0 -0
  259. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/spinner.py +0 -0
  260. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/state_handlers.py +0 -0
  261. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/styles.css +0 -0
  262. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/tui/widget_helpers.py +0 -0
  263. {codeplain-0.3.8 → codeplain-0.3.10.dev1}/usage_summary.py +0 -0
@@ -59,4 +59,31 @@ jobs:
59
59
  - name: Run E2E tests
60
60
  env:
61
61
  CODEPLAIN_API_KEY: ${{ secrets.CODEPLAIN_API_KEY }}
62
- run: pytest tests/e2e/ -v --tb=short
62
+ run: pytest tests/e2e/ -v --tb=short
63
+
64
+ notify-on-failure:
65
+ name: Notify Slack on failure
66
+ needs: [e2e-linux, e2e-windows]
67
+ if: failure()
68
+ runs-on: ubuntu-latest
69
+ env:
70
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_E2E_WEBHOOK_URL }}
71
+ steps:
72
+ - name: Determine failed platforms
73
+ id: platforms
74
+ run: |
75
+ failed=""
76
+ [ "${{ needs.e2e-linux.result }}" = "failure" ] && failed="Linux"
77
+ if [ "${{ needs.e2e-windows.result }}" = "failure" ]; then
78
+ [ -n "$failed" ] && failed="$failed and Windows" || failed="Windows"
79
+ fi
80
+ echo "failed=$failed" >> "$GITHUB_OUTPUT"
81
+
82
+ - name: Send failure notification to Slack
83
+ if: ${{ env.SLACK_WEBHOOK_URL != '' }}
84
+ uses: slackapi/slack-github-action@v1.24.0
85
+ with:
86
+ payload: |
87
+ {
88
+ "text": ${{ toJSON(format('[Codeplain Client] E2E tests FAILED on {0}. See <{1}/{2}/actions/runs/{3}|the run log>.', steps.platforms.outputs.failed, github.server_url, github.repository, github.run_id)) }}
89
+ }
@@ -0,0 +1,124 @@
1
+ name: PowerShell Install Scripts
2
+
3
+ on:
4
+ push:
5
+ paths:
6
+ - 'install/powershell/*.ps1'
7
+ - '.github/workflows/lint-powershell.yml'
8
+ pull_request:
9
+ paths:
10
+ - 'install/powershell/*.ps1'
11
+ - '.github/workflows/lint-powershell.yml'
12
+ workflow_dispatch:
13
+
14
+ jobs:
15
+ parse-windows-powershell-51:
16
+ name: Parse under Windows PowerShell 5.1
17
+ runs-on: windows-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ # The install scripts are fetched over HTTP and executed on stock Windows,
22
+ # where powershell.exe (5.1) is the default shell. 5.1 reads BOM-less files
23
+ # as ANSI (CP1252), so a non-ASCII glyph such as U+2713 decodes into a smart
24
+ # quote that silently terminates the enclosing string. The resulting parse
25
+ # errors point at unrelated lines far below the real cause, so parse every
26
+ # script with 5.1 explicitly rather than relying on PowerShell 7.
27
+ - name: Parse each script with 5.1
28
+ shell: powershell
29
+ run: |
30
+ $ErrorActionPreference = 'Stop'
31
+ Write-Host "PowerShell $($PSVersionTable.PSVersion) / ANSI codepage $([System.Text.Encoding]::Default.WebName)"
32
+
33
+ $failed = $false
34
+ Get-ChildItem 'install/powershell' -Filter *.ps1 | Sort-Object Name | ForEach-Object {
35
+ $errors = $null
36
+ [System.Management.Automation.Language.Parser]::ParseFile(
37
+ $_.FullName, [ref]$null, [ref]$errors) | Out-Null
38
+
39
+ if ($errors -and $errors.Count -gt 0) {
40
+ $failed = $true
41
+ Write-Host "FAIL $($_.Name): $($errors.Count) parse error(s)"
42
+ $errors | Sort-Object { $_.Extent.StartLineNumber } | ForEach-Object {
43
+ Write-Host " L$($_.Extent.StartLineNumber): $($_.Message)"
44
+ }
45
+ } else {
46
+ Write-Host "OK $($_.Name)"
47
+ }
48
+ }
49
+
50
+ if ($failed) { exit 1 }
51
+
52
+ # A BOM would fix file-based parsing but break `irm ... | iex`: PowerShell 5.1
53
+ # decodes an HTTP text/* body with no charset as ISO-8859-1, turning the BOM
54
+ # into literal "i>>?" text and failing with
55
+ # "The term 'i>>?$ErrorActionPreference' is not recognized".
56
+ # Keeping the sources pure ASCII is what makes both paths safe, so enforce it.
57
+ - name: Require pure ASCII and no BOM
58
+ shell: powershell
59
+ run: |
60
+ $ErrorActionPreference = 'Stop'
61
+ $failed = $false
62
+
63
+ Get-ChildItem 'install/powershell' -Filter *.ps1 | Sort-Object Name | ForEach-Object {
64
+ $fileBad = $false
65
+ $bytes = [System.IO.File]::ReadAllBytes($_.FullName)
66
+
67
+ if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
68
+ $failed = $true
69
+ $fileBad = $true
70
+ Write-Host "FAIL $($_.Name): has a UTF-8 BOM (breaks 'irm | iex'); remove it"
71
+ }
72
+
73
+ # Report line/column of any byte outside ASCII so the fix is obvious.
74
+ $text = [System.Text.Encoding]::UTF8.GetString($bytes)
75
+ $lineNo = 0
76
+ foreach ($line in ($text -split "`r?`n")) {
77
+ $lineNo++
78
+ for ($i = 0; $i -lt $line.Length; $i++) {
79
+ if ([int]$line[$i] -gt 127) {
80
+ $failed = $true
81
+ $fileBad = $true
82
+ $cp = "U+{0:X4}" -f [int]$line[$i]
83
+ Write-Host "FAIL $($_.Name) L${lineNo} C$($i + 1): non-ASCII $cp"
84
+ Write-Host " build it from its code point instead, e.g. `$CHECK = [char]0x2713"
85
+ break
86
+ }
87
+ }
88
+ }
89
+
90
+ if (-not $fileBad) { Write-Host "OK $($_.Name)" }
91
+ }
92
+
93
+ if ($failed) { exit 1 }
94
+
95
+ parse-powershell-7:
96
+ name: Parse under PowerShell 7
97
+ runs-on: windows-latest
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+
101
+ - name: Parse each script with 7
102
+ shell: pwsh
103
+ run: |
104
+ $ErrorActionPreference = 'Stop'
105
+ Write-Host "PowerShell $($PSVersionTable.PSVersion)"
106
+
107
+ $failed = $false
108
+ Get-ChildItem 'install/powershell' -Filter *.ps1 | Sort-Object Name | ForEach-Object {
109
+ $errors = $null
110
+ [System.Management.Automation.Language.Parser]::ParseFile(
111
+ $_.FullName, [ref]$null, [ref]$errors) | Out-Null
112
+
113
+ if ($errors -and $errors.Count -gt 0) {
114
+ $failed = $true
115
+ Write-Host "FAIL $($_.Name): $($errors.Count) parse error(s)"
116
+ $errors | Sort-Object { $_.Extent.StartLineNumber } | ForEach-Object {
117
+ Write-Host " L$($_.Extent.StartLineNumber): $($_.Message)"
118
+ }
119
+ } else {
120
+ Write-Host "OK $($_.Name)"
121
+ }
122
+ }
123
+
124
+ if ($failed) { exit 1 }
@@ -0,0 +1,135 @@
1
+ name: Publish dev build to PyPI
2
+
3
+ # Every merge to main publishes a PEP 440 dev release (e.g. 0.3.10.dev7) to
4
+ # PyPI, so the latest main is always installable from the real index with real
5
+ # dependency resolution. Dev releases are pre-releases: pip and uv skip them
6
+ # unless asked, so ordinary installs keep getting the latest stable.
7
+ #
8
+ # Tagged releases (including rc/beta/alpha) are handled by publish-to-pypi.yml.
9
+ on:
10
+ push:
11
+ branches: [main]
12
+ # Ad-hoc runs, e.g. re-publishing after a PyPI outage.
13
+ workflow_dispatch:
14
+
15
+ # Least privilege by default: jobs get no GITHUB_TOKEN scopes unless they
16
+ # opt in below.
17
+ permissions: {}
18
+
19
+ # Serialize publishes so versions land in merge order. Queued runs are not
20
+ # cancelled — each merge should still get its own dev build.
21
+ concurrency:
22
+ group: publish-dev-to-pypi
23
+ cancel-in-progress: false
24
+
25
+ jobs:
26
+ build:
27
+ name: Build dev distribution
28
+ runs-on: ubuntu-latest
29
+ permissions:
30
+ contents: read
31
+ outputs:
32
+ should-publish: ${{ steps.version.outputs.should-publish }}
33
+
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ with:
37
+ # hatch-vcs derives the version from git tags, so we need full history.
38
+ fetch-depth: 0
39
+
40
+ - name: Install uv
41
+ # uv provisions its own Python (honoring requires-python), so no
42
+ # separate actions/setup-python step is needed.
43
+ run: |
44
+ curl -LsSf https://astral.sh/uv/install.sh | sh
45
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
46
+
47
+ - name: Compute dev version
48
+ id: version
49
+ # Between releases hatch-vcs produces something like
50
+ # "0.3.10.dev16+gb710c2982". The "+g..." local version segment is valid
51
+ # PEP 440 but is rejected by PyPI on upload, so it has to go. We keep
52
+ # setuptools-scm's own next-version guess (0.3.10 — the patch bump
53
+ # after the latest tag) rather than re-deriving it here, and use the
54
+ # run number as the dev counter: it is strictly increasing, so each
55
+ # merge sorts after the last and re-runs never collide.
56
+ run: |
57
+ RAW=$(uvx --from setuptools-scm python -c \
58
+ "from setuptools_scm import get_version; print(get_version())")
59
+ echo "setuptools-scm reports: $RAW"
60
+
61
+ # On a commit that IS a release tag, setuptools-scm returns a clean
62
+ # version with no .dev component (e.g. "0.3.9" or "0.4.0rc1").
63
+ # Appending ".dev<run>" to that yields 0.3.9.dev42, which sorts BELOW
64
+ # the released 0.3.9 — newer code would look older. A tagged commit
65
+ # is a real release and is published by publish-to-pypi.yml, so there
66
+ # is no dev build to make here.
67
+ case "$RAW" in
68
+ *.dev*) ;;
69
+ *)
70
+ echo "::notice::$RAW is a tagged release; skipping dev build."
71
+ echo "should-publish=false" >> $GITHUB_OUTPUT
72
+ exit 0
73
+ ;;
74
+ esac
75
+
76
+ BASE=${RAW%%+*}
77
+ BASE=${BASE%%.dev*}
78
+ VERSION="${BASE}.dev${GITHUB_RUN_NUMBER}"
79
+ echo "Derived version: $RAW -> $VERSION"
80
+ echo "SETUPTOOLS_SCM_PRETEND_VERSION=$VERSION" >> $GITHUB_ENV
81
+ echo "should-publish=true" >> $GITHUB_OUTPUT
82
+
83
+ - name: Build package
84
+ if: steps.version.outputs.should-publish == 'true'
85
+ # hatch-vcs reads SETUPTOOLS_SCM_PRETEND_VERSION in place of the tag.
86
+ run: |
87
+ uv build
88
+ echo "Built distributions:"
89
+ ls -l dist/
90
+
91
+ - name: Store the distribution packages
92
+ if: steps.version.outputs.should-publish == 'true'
93
+ uses: actions/upload-artifact@v4
94
+ with:
95
+ name: dev-package-distributions
96
+ path: dist/
97
+
98
+ publish-dev:
99
+ name: Publish dev build to PyPI
100
+ needs: build
101
+ if: needs.build.outputs.should-publish == 'true'
102
+ runs-on: ubuntu-latest
103
+ environment:
104
+ name: pypi
105
+ url: https://pypi.org/p/codeplain
106
+ permissions:
107
+ # Mint a short-lived OIDC token so PyPI Trusted Publishing can
108
+ # authenticate this run — no long-lived API token needed.
109
+ id-token: write
110
+
111
+ env:
112
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
113
+
114
+ steps:
115
+ - name: Download distribution packages
116
+ uses: actions/download-artifact@v4
117
+ with:
118
+ name: dev-package-distributions
119
+ path: dist/
120
+
121
+ - name: Publish to PyPI
122
+ uses: pypa/gh-action-pypi-publish@release/v1
123
+ with:
124
+ # PyPI uploads are immutable, so a re-run of an already-published
125
+ # version should be a no-op, not a red build.
126
+ skip-existing: true
127
+
128
+ # Success is deliberately quiet: this runs on every merge to main, which
129
+ # is already announced elsewhere. Only failures ping.
130
+ - name: Notify Slack (failure)
131
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
132
+ run: |
133
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
134
+ -H 'Content-type: application/json' \
135
+ --data "{\"text\":\"*Codeplain Client*: Publishing dev build to PyPI FAILED :x: (commit \`${{ github.sha }}\`). See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
@@ -14,6 +14,9 @@ jobs:
14
14
  name: Upload to Cloudflare R2
15
15
  runs-on: ubuntu-latest
16
16
 
17
+ env:
18
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
19
+
17
20
  steps:
18
21
  - uses: actions/checkout@v4
19
22
 
@@ -54,3 +57,17 @@ jobs:
54
57
  --content-type "text/plain"
55
58
  echo "✓ examples.ps1 uploaded to R2"
56
59
 
60
+ - name: Notify Slack (success)
61
+ if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
62
+ run: |
63
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
64
+ -H 'Content-type: application/json' \
65
+ --data "{\"text\":\"*Codeplain Client*: Install scripts deployed to R2 :white_check_mark: (\`${GITHUB_SHA:0:7}\`, by *${{ github.actor }}*).\"}"
66
+
67
+ - name: Notify Slack (failure)
68
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
69
+ run: |
70
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
71
+ -H 'Content-type: application/json' \
72
+ --data "{\"text\":\"*Codeplain Client*: Install script deploy to R2 FAILED :x: (\`${GITHUB_SHA:0:7}\`). Users may be getting a stale installer. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
73
+
@@ -0,0 +1,117 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ # Least privilege by default: jobs get no GITHUB_TOKEN scopes unless they
8
+ # opt in below.
9
+ permissions: {}
10
+
11
+ jobs:
12
+ build:
13
+ name: Build distribution
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: write
17
+
18
+ env:
19
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ with:
24
+ # hatch-vcs derives the version from git tags, so we need full history.
25
+ fetch-depth: 0
26
+
27
+ - name: Notify Slack (start)
28
+ if: ${{ env.SLACK_WEBHOOK_URL != '' }}
29
+ run: |
30
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
31
+ -H 'Content-type: application/json' \
32
+ --data "{\"text\":\"*Codeplain Client*: Release \`${{ github.ref_name }}\` published by *${{ github.actor }}* — building and publishing to PyPI...\"}"
33
+
34
+ - name: Install uv
35
+ # uv provisions its own Python (honoring requires-python), so no
36
+ # separate actions/setup-python step is needed.
37
+ run: |
38
+ curl -LsSf https://astral.sh/uv/install.sh | sh
39
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
40
+
41
+ - name: Build package
42
+ # hatch-vcs reads the version straight from the release tag.
43
+ run: |
44
+ uv build
45
+ echo "Built distributions:"
46
+ ls -l dist/
47
+
48
+ - name: Store the distribution packages
49
+ uses: actions/upload-artifact@v4
50
+ with:
51
+ name: python-package-distributions
52
+ path: dist/
53
+
54
+ - name: Upload assets to GitHub Release
55
+ env:
56
+ GH_TOKEN: ${{ github.token }}
57
+ run: |
58
+ gh release upload ${{ github.ref_name }} dist/* --clobber
59
+
60
+ - name: Notify Slack (build failure)
61
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
62
+ run: |
63
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
64
+ -H 'Content-type: application/json' \
65
+ --data "{\"text\":\"*Codeplain Client*: Build of \`${{ github.ref_name }}\` FAILED :x:. Nothing was published to PyPI. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
66
+
67
+ publish-to-pypi:
68
+ name: Publish to PyPI
69
+ needs: build
70
+ runs-on: ubuntu-latest
71
+ environment:
72
+ name: pypi
73
+ url: https://pypi.org/p/codeplain
74
+ permissions:
75
+ # Mint a short-lived OIDC token so PyPI Trusted Publishing can
76
+ # authenticate this run — no long-lived API token needed.
77
+ id-token: write
78
+
79
+ env:
80
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
81
+
82
+ steps:
83
+ - name: Download distribution packages
84
+ uses: actions/download-artifact@v4
85
+ with:
86
+ name: python-package-distributions
87
+ path: dist/
88
+
89
+ - name: Publish to PyPI
90
+ uses: pypa/gh-action-pypi-publish@release/v1
91
+
92
+ - name: Notify Slack (success)
93
+ if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
94
+ env:
95
+ # GitHub marks the release itself as a pre-release; the tag
96
+ # (v0.4.0rc1) carries the same intent for PEP 440.
97
+ IS_PRERELEASE: ${{ github.event.release.prerelease }}
98
+ TAG: ${{ github.ref_name }}
99
+ run: |
100
+ VERSION="${TAG#v}"
101
+ if [ "$IS_PRERELEASE" = "true" ]; then
102
+ # pip and uv skip pre-releases by default, so "--upgrade" would
103
+ # NOT pick this up. Tell people the command that actually works.
104
+ TEXT="*Codeplain Client*: pre-release \`$TAG\` published to PyPI :test_tube:. Normal installs are unaffected — try it with \`pip install --pre codeplain==$VERSION\`."
105
+ else
106
+ TEXT="*Codeplain Client*: \`$TAG\` published to PyPI :white_check_mark:. Install with \`pip install --upgrade codeplain\`."
107
+ fi
108
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
109
+ -H 'Content-type: application/json' \
110
+ --data "$(jq -n --arg t "$TEXT" '{text:$t}')"
111
+
112
+ - name: Notify Slack (failure)
113
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
114
+ run: |
115
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
116
+ -H 'Content-type: application/json' \
117
+ --data "{\"text\":\"*Codeplain Client*: Publishing \`${{ github.ref_name }}\` to PyPI FAILED :x:. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
@@ -14,14 +14,14 @@ The codebase serves two audiences:
14
14
  - **End users**: developers who write `***plain` specs and run `plain2code.py` to generate code
15
15
  - **Internal devs**: maintaining the renderer itself (this codebase)
16
16
 
17
- ### Related Repository: plain2code_rest_api
17
+ ### Related Repository: codeplain-api
18
18
 
19
- This repository has a sibling repository **`plain2code_rest_api`** which contains the backend API service that this client communicates with. The two repositories are typically cloned as siblings:
19
+ This repository has a sibling repository **`codeplain-api`** which contains the backend API service that this client communicates with. The two repositories are typically cloned as siblings:
20
20
 
21
21
  ```
22
22
  parent-directory/
23
- ├── codeplain/ # This repository (client)
24
- └── plain2code_rest_api/ # Backend API service
23
+ ├── codeplain/ # This repository (client)
24
+ └── codeplain-api/ # Backend API service
25
25
  ```
26
26
 
27
27
  **When to work across both repositories:**
@@ -212,8 +212,12 @@ Two logging modes:
212
212
  ### Code Generation Process
213
213
  - Templates in `standard_template_library/` use Liquid2 syntax
214
214
  - Template search order: (1) `.plain` file dir, (2) `--template-dir`, (3) built-in standard lib
215
- - Generated code written to `build/` (configurable via `--build-folder`)
216
- - Each FRID render produces a git commit in build folder for rollback capability
215
+ - Each module renders into its own tree under the build folder (configurable via `--build-folder`, default `plain_modules/`):
216
+ - `<build-folder>/<module>/code/` implementation code (its own git repo)
217
+ - `<build-folder>/<module>/tests/` — conformance tests (its own git repo; only created when a conformance tests script is configured)
218
+ - `<build-folder>/<module>/.codeplain/` — module metadata (`module_metadata.json`), not tracked in git
219
+ - `<build-folder>/<module>/.memory/` — conformance test memory, not tracked in git
220
+ - Each FRID render produces a git commit in the `code/` and `tests/` repos for rollback capability
217
221
 
218
222
  ### Configuration
219
223
  - `config.yaml` can be placed in `.plain` file dir or CWD
@@ -0,0 +1,137 @@
1
+ # Contributing to Codeplain
2
+
3
+ Thanks for contributing to Codeplain.
4
+
5
+ ## Before You Start
6
+
7
+ Check existing issues and pull requests before starting work.
8
+
9
+ Keep each contribution focused on one issue or a closely related set of changes.
10
+
11
+ ## Contribution Workflow
12
+
13
+ 1. Fork the Codeplain repository.
14
+ 2. Make your changes on a branch in your fork.
15
+ 3. Commit and push the changes to your fork.
16
+ 4. Open a pull request against the Codeplain `main` branch.
17
+
18
+ ## Configure Codeplain
19
+
20
+ Use your own Codeplain API key for local development and testing.
21
+
22
+ Never commit API keys, credentials, or other secrets.
23
+
24
+ ## Test with a Plain Example
25
+
26
+ When relevant, test your change with an existing example from the `plainlang-examples` repository.
27
+
28
+ This provides a real `.plain` project for verifying the change in an actual Codeplain workflow.
29
+
30
+ ## Run Tests
31
+
32
+ Run the tests relevant to your change before opening a pull request.
33
+
34
+ For changes that affect the CLI, rendering, or test execution, also test the change by running the relevant Codeplain command from the terminal.
35
+
36
+ Check that:
37
+
38
+ * the command returns the expected exit code,
39
+ * errors are clear and do not expose unintended tracebacks,
40
+ * existing Codeplain behavior still works.
41
+
42
+ For platform-specific changes, test the relevant `.sh` or `.ps1` workflow.
43
+
44
+ ## Keep the Change Clean
45
+
46
+ Before submitting:
47
+
48
+ * remove temporary files and debugging output,
49
+ * avoid unrelated changes,
50
+ * add or update tests where needed,
51
+ * update documentation when behavior changes,
52
+ * verify that no secrets are included.
53
+
54
+ Review your changes with:
55
+
56
+ ```bash
57
+ git status
58
+ git diff
59
+ ```
60
+
61
+ ## Pull Request
62
+
63
+ Include:
64
+
65
+ * what changed,
66
+ * why it changed,
67
+ * the related issue, when applicable,
68
+ * how the change was tested,
69
+ * the `plainlang-examples` example used, when relevant.
70
+
71
+ ## Pre-Releases
72
+
73
+ Everything below happens on real PyPI — there is no separate test index.
74
+ Pre-releases are invisible to ordinary installs: pip and uv skip them during
75
+ resolution, so `pip install codeplain` and `pip install --upgrade codeplain`
76
+ always serve the latest *stable* release.
77
+
78
+ ### Dev builds (automatic)
79
+
80
+ Every merge to `main` publishes a dev release such as `0.3.10.dev7`, so the tip
81
+ of main is always installable from the real index:
82
+
83
+ ```bash
84
+ pip install --pre codeplain==0.3.10.dev7
85
+ uv tool install --prerelease allow codeplain
86
+ ```
87
+
88
+ Versions are `<next-patch>.dev<run-number>`, so they sort after the last
89
+ release and before the next one. See `.github/workflows/publish-dev-to-pypi.yml`.
90
+ If that workflow is ever dispatched against a commit that is itself a release
91
+ tag, it skips rather than publishing a dev build that would sort below the
92
+ release.
93
+
94
+ ### Release candidates (manual)
95
+
96
+ To get a specific build in front of people before it becomes the default
97
+ install, cut a PEP 440 pre-release.
98
+
99
+ Tag and publish a GitHub release as usual, but with a pre-release version and
100
+ the release marked "pre-release":
101
+
102
+ ```
103
+ v0.4.0a1 alpha
104
+ v0.4.0b1 beta
105
+ v0.4.0rc1 release candidate
106
+ ```
107
+
108
+ `publish-to-pypi.yml` handles these with no special casing: hatch-vcs reads the
109
+ version straight off the tag (`v0.4.0rc1` -> `0.4.0rc1`).
110
+
111
+ Opt in the same way:
112
+
113
+ ```bash
114
+ pip install --pre codeplain==0.4.0rc1
115
+ ```
116
+
117
+ ### Which API a build talks to
118
+
119
+ Pre-release builds default to the **test** API, so an unreleased client is
120
+ exercised against the unreleased backend:
121
+
122
+ | build | default API |
123
+ | --- | --- |
124
+ | stable release (`0.3.9`) | `https://api.codeplain.ai` |
125
+ | dev build (`0.3.10.dev7`) | `https://api.test.codeplain.ai` |
126
+ | alpha/beta/rc (`0.4.0rc1`) | `https://api.test.codeplain.ai` |
127
+
128
+ `--api` always overrides this. Resolution lives in
129
+ `system_config._resolve_default_api_url`, keyed off the version baked into the
130
+ package at build time — so nothing needs configuring at install time.
131
+
132
+ A source checkout reports the nearest git tag as its version, so it is treated
133
+ as stable and keeps pointing at production; use `--api` to aim it elsewhere.
134
+
135
+ Because every build above goes to real PyPI, dependency resolution and the
136
+ install path are exactly what an end user gets — the main reason this is
137
+ preferred over publishing to TestPyPI.