codeplain 0.3.8__tar.gz → 0.3.10__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 (271) hide show
  1. codeplain-0.3.10/.github/dependabot.yml +28 -0
  2. codeplain-0.3.10/.github/workflows/e2e.yml +91 -0
  3. {codeplain-0.3.8 → codeplain-0.3.10}/.github/workflows/lint-and-test.yml +19 -17
  4. codeplain-0.3.10/.github/workflows/lint-powershell.yml +124 -0
  5. {codeplain-0.3.8 → codeplain-0.3.10}/.github/workflows/nofity-slack-on-main-merge.yml +3 -3
  6. codeplain-0.3.10/.github/workflows/publish-dev-to-pypi.yml +147 -0
  7. {codeplain-0.3.8 → codeplain-0.3.10}/.github/workflows/publish-install-script.yml +18 -1
  8. codeplain-0.3.10/.github/workflows/publish-to-pypi.yml +159 -0
  9. {codeplain-0.3.8 → codeplain-0.3.10}/CLAUDE.md +10 -6
  10. codeplain-0.3.10/CONTRIBUTING.md +137 -0
  11. {codeplain-0.3.8 → codeplain-0.3.10}/PKG-INFO +36 -8
  12. {codeplain-0.3.8 → codeplain-0.3.10}/README.md +31 -3
  13. {codeplain-0.3.8 → codeplain-0.3.10}/codeplain_REST_api.py +6 -14
  14. {codeplain-0.3.8 → codeplain-0.3.10}/concept_utils.py +6 -0
  15. codeplain-0.3.10/conformance_fix_journal.py +207 -0
  16. {codeplain-0.3.8 → codeplain-0.3.10}/docs/plain2code_cli.md +25 -23
  17. {codeplain-0.3.8 → codeplain-0.3.10}/docs/starting_a_plain_project_from_scratch.md +8 -2
  18. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_golang/run.sh +2 -2
  19. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_python/run.sh +2 -2
  20. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/run.sh +1 -1
  21. {codeplain-0.3.8 → codeplain-0.3.10}/git_utils.py +0 -10
  22. {codeplain-0.3.8 → codeplain-0.3.10}/install/bash/install.sh +41 -0
  23. {codeplain-0.3.8 → codeplain-0.3.10}/install/powershell/examples.ps1 +11 -5
  24. {codeplain-0.3.8 → codeplain-0.3.10}/install/powershell/install.ps1 +131 -19
  25. codeplain-0.3.10/install/powershell/walkthrough.ps1 +174 -0
  26. codeplain-0.3.10/memory_management.py +52 -0
  27. codeplain-0.3.10/metadata_utils.py +46 -0
  28. {codeplain-0.3.8 → codeplain-0.3.10}/module_renderer.py +9 -6
  29. {codeplain-0.3.8 → codeplain-0.3.10}/partial_rendering.py +35 -4
  30. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code.py +52 -4
  31. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_arguments.py +13 -19
  32. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_cli.md +17 -19
  33. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_console.py +3 -1
  34. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_exceptions.py +8 -0
  35. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_logger.py +37 -15
  36. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_telemetry.py +17 -11
  37. {codeplain-0.3.8 → codeplain-0.3.10}/plain_file.py +18 -1
  38. {codeplain-0.3.8 → codeplain-0.3.10}/plain_modules.py +264 -42
  39. {codeplain-0.3.8 → codeplain-0.3.10}/pyproject.toml +3 -3
  40. codeplain-0.3.10/render_machine/actions/distill_conformance_test_memory.py +56 -0
  41. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/fix_conformance_test.py +58 -29
  42. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/prepare_repositories.py +16 -10
  43. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/run_conformance_tests.py +5 -11
  44. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/conformance_tests.py +48 -9
  45. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/implementation_code_helpers.py +5 -1
  46. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/render_context.py +14 -4
  47. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/render_types.py +0 -4
  48. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/render_utils.py +1 -2
  49. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/state_machine_config.py +10 -1
  50. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/states.py +1 -0
  51. {codeplain-0.3.8 → codeplain-0.3.10}/requirements.txt +3 -3
  52. codeplain-0.3.10/system_config.py +148 -0
  53. {codeplain-0.3.8 → codeplain-0.3.10}/tests/e2e/test_hello_world_python.py +1 -1
  54. {codeplain-0.3.8 → codeplain-0.3.10}/tests/e2e/test_hello_world_python_windows.py +1 -1
  55. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_arg_provenance.py +3 -3
  56. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_cli_output.py +13 -0
  57. codeplain-0.3.10/tests/test_conformance_fix_journal.py +259 -0
  58. codeplain-0.3.10/tests/test_distill_conformance_test_memory.py +145 -0
  59. codeplain-0.3.10/tests/test_dry_run_link_validation.py +60 -0
  60. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_folder_path_resolution.py +12 -13
  61. codeplain-0.3.10/tests/test_headless_logging.py +177 -0
  62. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plain2code.py +1 -2
  63. codeplain-0.3.10/tests/test_plain_modules.py +794 -0
  64. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plainfileparser.py +41 -4
  65. codeplain-0.3.10/tests/test_prepare_repositories_layout.py +315 -0
  66. codeplain-0.3.10/tests/test_system_config.py +95 -0
  67. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_telemetry.py +31 -10
  68. {codeplain-0.3.8 → codeplain-0.3.10}/tui/plain_module_render_choice_tui.py +25 -8
  69. {codeplain-0.3.8 → codeplain-0.3.10}/tui/state_handlers.py +7 -1
  70. codeplain-0.3.8/.github/dependabot.yml +0 -11
  71. codeplain-0.3.8/.github/workflows/e2e.yml +0 -62
  72. codeplain-0.3.8/.github/workflows/publish-to-pypi.yml +0 -70
  73. codeplain-0.3.8/install/powershell/walkthrough.ps1 +0 -161
  74. codeplain-0.3.8/memory_management.py +0 -133
  75. codeplain-0.3.8/system_config.py +0 -68
  76. codeplain-0.3.8/tests/test_plain_modules.py +0 -343
  77. {codeplain-0.3.8 → codeplain-0.3.10}/.claude/settings.json +0 -0
  78. {codeplain-0.3.8 → codeplain-0.3.10}/.flake8 +0 -0
  79. {codeplain-0.3.8 → codeplain-0.3.10}/.gitignore +0 -0
  80. {codeplain-0.3.8 → codeplain-0.3.10}/.vscode/launch.json +0 -0
  81. {codeplain-0.3.8 → codeplain-0.3.10}/.vscode/settings.json +0 -0
  82. {codeplain-0.3.8 → codeplain-0.3.10}/LICENSE +0 -0
  83. {codeplain-0.3.8 → codeplain-0.3.10}/change_detection.py +0 -0
  84. {codeplain-0.3.8 → codeplain-0.3.10}/cli_output/__init__.py +0 -0
  85. {codeplain-0.3.8 → codeplain-0.3.10}/cli_output/dry_run.py +0 -0
  86. {codeplain-0.3.8 → codeplain-0.3.10}/cli_output/render_summary.py +0 -0
  87. {codeplain-0.3.8 → codeplain-0.3.10}/cli_output/status.py +0 -0
  88. {codeplain-0.3.8 → codeplain-0.3.10}/config/__init__.py +0 -0
  89. {codeplain-0.3.8 → codeplain-0.3.10}/config/system_config.yaml +0 -0
  90. {codeplain-0.3.8 → codeplain-0.3.10}/diff_utils.py +0 -0
  91. {codeplain-0.3.8 → codeplain-0.3.10}/docs/generate_cli.py +0 -0
  92. {codeplain-0.3.8 → codeplain-0.3.10}/event_bus.py +0 -0
  93. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_golang/config.yaml +0 -0
  94. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  95. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  96. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_python/config.yaml +0 -0
  97. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  98. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  99. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/config.yaml +0 -0
  100. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  101. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  102. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  103. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  104. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  105. {codeplain-0.3.8 → codeplain-0.3.10}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  106. {codeplain-0.3.8 → codeplain-0.3.10}/examples/run.sh +0 -0
  107. {codeplain-0.3.8 → codeplain-0.3.10}/file_utils.py +0 -0
  108. {codeplain-0.3.8 → codeplain-0.3.10}/install/bash/examples.sh +0 -0
  109. {codeplain-0.3.8 → codeplain-0.3.10}/install/bash/walkthrough.sh +0 -0
  110. {codeplain-0.3.8 → codeplain-0.3.10}/path_resolution.py +0 -0
  111. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_events.py +0 -0
  112. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_nodes.py +0 -0
  113. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_read_config.py +0 -0
  114. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_state.py +0 -0
  115. {codeplain-0.3.8 → codeplain-0.3.10}/plain2code_utils.py +0 -0
  116. {codeplain-0.3.8 → codeplain-0.3.10}/plain_spec.py +0 -0
  117. {codeplain-0.3.8 → codeplain-0.3.10}/pytest.ini +0 -0
  118. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/__init__.py +0 -0
  119. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  120. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/base_action.py +0 -0
  121. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  122. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  123. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/create_dist.py +0 -0
  124. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/exit_with_error.py +0 -0
  125. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/finish_functional_requirement.py +0 -0
  126. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/fix_unit_tests.py +0 -0
  127. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/prepare_testing_environment.py +0 -0
  128. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/refactor_code.py +0 -0
  129. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/render_conformance_tests.py +0 -0
  130. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/render_functional_requirement.py +0 -0
  131. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/run_unit_tests.py +0 -0
  132. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/actions/summarize_conformance_tests.py +0 -0
  133. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/code_renderer.py +0 -0
  134. {codeplain-0.3.8 → codeplain-0.3.10}/render_machine/triggers.py +0 -0
  135. {codeplain-0.3.8 → codeplain-0.3.10}/resources/codeplain_overview.png +0 -0
  136. {codeplain-0.3.8 → codeplain-0.3.10}/resources/plain_example.png +0 -0
  137. {codeplain-0.3.8 → codeplain-0.3.10}/standard_template_library/golang-console-app-template.plain +0 -0
  138. {codeplain-0.3.8 → codeplain-0.3.10}/standard_template_library/python-console-app-template.plain +0 -0
  139. {codeplain-0.3.8 → codeplain-0.3.10}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  140. {codeplain-0.3.8 → codeplain-0.3.10}/standard_template_library/typescript-react-app-template.plain +0 -0
  141. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  142. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  143. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  144. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_golang.sh +0 -0
  145. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  146. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_conformance_tests_python.sh +0 -0
  147. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_flutter.ps1 +0 -0
  148. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_flutter.sh +0 -0
  149. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_golang.ps1 +0 -0
  150. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_golang.sh +0 -0
  151. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_python.ps1 +0 -0
  152. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_python.sh +0 -0
  153. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_react.ps1 +0 -0
  154. {codeplain-0.3.8 → codeplain-0.3.10}/test_scripts/run_unittests_react.sh +0 -0
  155. {codeplain-0.3.8 → codeplain-0.3.10}/tests/__init__.py +0 -0
  156. {codeplain-0.3.8 → codeplain-0.3.10}/tests/conftest.py +0 -0
  157. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
  158. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
  159. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/circular_imports_1.plain +0 -0
  160. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/circular_imports_2.plain +0 -0
  161. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/circular_imports_main.plain +0 -0
  162. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/diamond_import_1.plain +0 -0
  163. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/diamond_import_2.plain +0 -0
  164. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/diamond_import_common.plain +0 -0
  165. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/diamond_imports_main.plain +0 -0
  166. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/import_with_functionalities.plain +0 -0
  167. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
  168. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/imports/non_existent_import.plain +0 -0
  169. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_code_var.plain +0 -0
  170. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_implement.plain +0 -0
  171. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  172. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_middle.plain +0 -0
  173. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_root.plain +0 -0
  174. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/partial_rendering/pr_solo.plain +0 -0
  175. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
  176. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  177. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
  178. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  179. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  180. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
  181. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  182. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  183. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
  184. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  185. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  186. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  187. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  188. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  189. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  190. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  191. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  192. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  193. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  194. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  195. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  196. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  197. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  198. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  199. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  200. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  201. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  202. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  203. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  204. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  205. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  206. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  207. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  208. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  209. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  210. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts.plain +0 -0
  211. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  212. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  213. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  214. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  215. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  216. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  217. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  218. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  219. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/topological_sort.plain +0 -0
  220. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  221. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/circular_requires_main.plain +0 -0
  222. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/circular_requires_sub.plain +0 -0
  223. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/diamond_requires_1.plain +0 -0
  224. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/diamond_requires_2.plain +0 -0
  225. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/diamond_requires_common.plain +0 -0
  226. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/diamond_requires_main.plain +0 -0
  227. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/independent_requires_1.plain +0 -0
  228. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/independent_requires_2.plain +0 -0
  229. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/independent_requires_main.plain +0 -0
  230. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/non_existent_require.plain +0 -0
  231. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/normal_requires_1.plain +0 -0
  232. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/normal_requires_2.plain +0 -0
  233. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/normal_requires_common.plain +0 -0
  234. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/requires/normal_requires_main.plain +0 -0
  235. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/sample_base64_image.txt +0 -0
  236. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/simple.plain +0 -0
  237. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/block_level_include.plain +0 -0
  238. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/code_variables.plain +0 -0
  239. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/header.plain +0 -0
  240. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/implement.plain +0 -0
  241. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/implement_2.plain +0 -0
  242. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/template_include.plain +0 -0
  243. {codeplain-0.3.8 → codeplain-0.3.10}/tests/data/templates/test_hardest_problem.plain +0 -0
  244. {codeplain-0.3.8 → codeplain-0.3.10}/tests/e2e/Dockerfile +0 -0
  245. {codeplain-0.3.8 → codeplain-0.3.10}/tests/e2e/conftest.py +0 -0
  246. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_change_detection.py +0 -0
  247. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_console_log_styles.py +0 -0
  248. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_file_utils.py +0 -0
  249. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_git_utils.py +0 -0
  250. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_imports.py +0 -0
  251. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_log_file_name_resolution.py +0 -0
  252. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_logging_config_path_resolution.py +0 -0
  253. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_partial_rendering.py +0 -0
  254. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_path_resolution.py +0 -0
  255. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plain2code_state.py +0 -0
  256. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plain2code_utils.py +0 -0
  257. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plainfile.py +0 -0
  258. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_plainspec.py +0 -0
  259. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_requires.py +0 -0
  260. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_resolve_config_file.py +0 -0
  261. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_script_path_resolution.py +0 -0
  262. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_tui_usage.py +0 -0
  263. {codeplain-0.3.8 → codeplain-0.3.10}/tests/test_usage_summary.py +0 -0
  264. {codeplain-0.3.8 → codeplain-0.3.10}/tui/__init__.py +0 -0
  265. {codeplain-0.3.8 → codeplain-0.3.10}/tui/components.py +0 -0
  266. {codeplain-0.3.8 → codeplain-0.3.10}/tui/models.py +0 -0
  267. {codeplain-0.3.8 → codeplain-0.3.10}/tui/plain2code_tui.py +0 -0
  268. {codeplain-0.3.8 → codeplain-0.3.10}/tui/spinner.py +0 -0
  269. {codeplain-0.3.8 → codeplain-0.3.10}/tui/styles.css +0 -0
  270. {codeplain-0.3.8 → codeplain-0.3.10}/tui/widget_helpers.py +0 -0
  271. {codeplain-0.3.8 → codeplain-0.3.10}/usage_summary.py +0 -0
@@ -0,0 +1,28 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 3
8
+ commit-message:
9
+ prefix: "dependabot"
10
+ labels:
11
+ - "dependencies"
12
+
13
+ # Keeps the SHA-pinned actions in publish-to-pypi.yml patched.
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ open-pull-requests-limit: 5
19
+ commit-message:
20
+ prefix: "ci"
21
+ labels:
22
+ - "dependencies"
23
+ - "github-actions"
24
+ groups:
25
+ actions-minor-and-patch:
26
+ update-types:
27
+ - "minor"
28
+ - "patch"
@@ -0,0 +1,91 @@
1
+ # .github/workflows/e2e.yml
2
+ name: E2E
3
+
4
+ on:
5
+ schedule:
6
+ - cron: '0 5 * * 1-5' # weekday nights to catch API drift
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ e2e-linux:
11
+ runs-on: ubuntu-latest
12
+ timeout-minutes: 15
13
+ steps:
14
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
15
+
16
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
17
+ with:
18
+ python-version: '3.12'
19
+
20
+ - run: pip install pytest
21
+
22
+ - name: Set up Docker Buildx
23
+ uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
24
+
25
+ - name: Build E2E image (cached)
26
+ uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
27
+ with:
28
+ context: .
29
+ file: tests/e2e/Dockerfile
30
+ tags: codeplain-e2e:latest
31
+ load: true
32
+ cache-from: type=gha
33
+ cache-to: type=gha,mode=max
34
+
35
+ - name: Run E2E tests
36
+ env:
37
+ CODEPLAIN_API_KEY: ${{ secrets.CODEPLAIN_API_KEY }}
38
+ run: pytest tests/e2e/ -v --tb=short
39
+
40
+ - name: Upload generated outputs on failure
41
+ if: failure()
42
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
43
+ with:
44
+ name: e2e-outputs-linux
45
+ path: /tmp/pytest-of-runner/**/container_work*/**
46
+
47
+ e2e-windows:
48
+ runs-on: windows-latest
49
+ timeout-minutes: 15
50
+ steps:
51
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
+
53
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
54
+ with:
55
+ python-version: '3.12'
56
+
57
+ - run: pip install pytest
58
+
59
+ - name: Run E2E tests
60
+ env:
61
+ CODEPLAIN_API_KEY: ${{ secrets.CODEPLAIN_API_KEY }}
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@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
85
+ with:
86
+ webhook: ${{ env.SLACK_WEBHOOK_URL }}
87
+ webhook-type: incoming-webhook
88
+ payload: |
89
+ {
90
+ "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)) }}
91
+ }
@@ -12,13 +12,13 @@ jobs:
12
12
  name: Black Formatting
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16
16
  - name: Set up Python
17
- uses: actions/setup-python@v5
17
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
18
18
  with:
19
19
  python-version: ${{ env.PYTHON_VERSION }}
20
20
  - name: Cache pip
21
- uses: actions/cache@v4
21
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
22
22
  with:
23
23
  path: ~/.cache/pip
24
24
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -33,13 +33,13 @@ jobs:
33
33
  name: Import Sorting
34
34
  runs-on: ubuntu-latest
35
35
  steps:
36
- - uses: actions/checkout@v4
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
37
  - name: Set up Python
38
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
39
39
  with:
40
40
  python-version: ${{ env.PYTHON_VERSION }}
41
41
  - name: Cache pip
42
- uses: actions/cache@v4
42
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
43
43
  with:
44
44
  path: ~/.cache/pip
45
45
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -54,13 +54,13 @@ jobs:
54
54
  name: Flake8 Linting
55
55
  runs-on: ubuntu-latest
56
56
  steps:
57
- - uses: actions/checkout@v4
57
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
58
58
  - name: Set up Python
59
- uses: actions/setup-python@v5
59
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
60
60
  with:
61
61
  python-version: ${{ env.PYTHON_VERSION }}
62
62
  - name: Cache pip
63
- uses: actions/cache@v4
63
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
64
64
  with:
65
65
  path: ~/.cache/pip
66
66
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -75,13 +75,13 @@ jobs:
75
75
  name: MyPy Type Checking
76
76
  runs-on: ubuntu-latest
77
77
  steps:
78
- - uses: actions/checkout@v4
78
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
79
  - name: Set up Python
80
- uses: actions/setup-python@v5
80
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
81
81
  with:
82
82
  python-version: ${{ env.PYTHON_VERSION }}
83
83
  - name: Cache pip
84
- uses: actions/cache@v4
84
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
85
85
  with:
86
86
  path: ~/.cache/pip
87
87
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -96,9 +96,9 @@ jobs:
96
96
  name: Run Tests
97
97
  runs-on: ubuntu-latest
98
98
  steps:
99
- - uses: actions/checkout@v4
99
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
100
100
  - name: Set up Python
101
- uses: actions/setup-python@v5
101
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
102
102
  with:
103
103
  python-version: ${{ env.PYTHON_VERSION }}
104
104
  - name: Configure git for tests
@@ -107,7 +107,7 @@ jobs:
107
107
  git config --global user.name "Test Runner"
108
108
  git config --global init.defaultBranch main
109
109
  - name: Cache pip
110
- uses: actions/cache@v4
110
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
111
111
  with:
112
112
  path: ~/.cache/pip
113
113
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -122,5 +122,7 @@ jobs:
122
122
  coverage run -m pytest tests/ -v
123
123
  coverage xml
124
124
  coverage report
125
- - name: Upload coverage reports
126
- uses: codecov/codecov-action@v3
125
+ # Disabled: v3's Node runtime is gone from the runners. Re-enable with a
126
+ # current major version, which renamed several inputs.
127
+ # - name: Upload coverage reports
128
+ # uses: codecov/codecov-action@v3
@@ -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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
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 }
@@ -12,11 +12,11 @@ jobs:
12
12
  if: github.event.pull_request.merged == true
13
13
  steps:
14
14
  - name: Send notification to Slack
15
- uses: slackapi/slack-github-action@v1.24.0
15
+ uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
16
16
  with:
17
+ webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
18
+ webhook-type: incoming-webhook
17
19
  payload: |
18
20
  {
19
21
  "text": ${{ toJSON(format('[Codeplain Client] PR <{0}|#{1}: {2}> was merged to main by `{3}`.', github.event.pull_request.html_url, github.event.pull_request.number, github.event.pull_request.title, github.actor)) }}
20
22
  }
21
- env:
22
- SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -0,0 +1,147 @@
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
+ version: ${{ steps.version.outputs.version }}
34
+
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ with:
38
+ # hatch-vcs derives the version from git tags, so we need full history.
39
+ fetch-depth: 0
40
+
41
+ - name: Install uv
42
+ # uv provisions its own Python (honoring requires-python), so no
43
+ # separate actions/setup-python step is needed.
44
+ run: |
45
+ curl -LsSf https://astral.sh/uv/install.sh | sh
46
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
47
+
48
+ - name: Compute dev version
49
+ id: version
50
+ # Between releases hatch-vcs produces something like
51
+ # "0.3.10.dev16+gb710c2982". The "+g..." local version segment is valid
52
+ # PEP 440 but is rejected by PyPI on upload, so it has to go. We keep
53
+ # setuptools-scm's own next-version guess (0.3.10 — the patch bump
54
+ # after the latest tag) rather than re-deriving it here, and use the
55
+ # run number as the dev counter: it is strictly increasing, so each
56
+ # merge sorts after the last and re-runs never collide.
57
+ run: |
58
+ RAW=$(uvx --from setuptools-scm python -c \
59
+ "from setuptools_scm import get_version; print(get_version())")
60
+ echo "setuptools-scm reports: $RAW"
61
+
62
+ # On a commit that IS a release tag, setuptools-scm returns a clean
63
+ # version with no .dev component (e.g. "0.3.9" or "0.4.0rc1").
64
+ # Appending ".dev<run>" to that yields 0.3.9.dev42, which sorts BELOW
65
+ # the released 0.3.9 — newer code would look older. A tagged commit
66
+ # is a real release and is published by publish-to-pypi.yml, so there
67
+ # is no dev build to make here.
68
+ case "$RAW" in
69
+ *.dev*) ;;
70
+ *)
71
+ echo "::notice::$RAW is a tagged release; skipping dev build."
72
+ echo "should-publish=false" >> $GITHUB_OUTPUT
73
+ exit 0
74
+ ;;
75
+ esac
76
+
77
+ BASE=${RAW%%+*}
78
+ BASE=${BASE%%.dev*}
79
+ VERSION="${BASE}.dev${GITHUB_RUN_NUMBER}"
80
+ echo "Derived version: $RAW -> $VERSION"
81
+ echo "SETUPTOOLS_SCM_PRETEND_VERSION=$VERSION" >> $GITHUB_ENV
82
+ echo "should-publish=true" >> $GITHUB_OUTPUT
83
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
84
+
85
+ - name: Build package
86
+ if: steps.version.outputs.should-publish == 'true'
87
+ # hatch-vcs reads SETUPTOOLS_SCM_PRETEND_VERSION in place of the tag.
88
+ run: |
89
+ uv build
90
+ echo "Built distributions:"
91
+ ls -l dist/
92
+
93
+ - name: Store the distribution packages
94
+ if: steps.version.outputs.should-publish == 'true'
95
+ uses: actions/upload-artifact@v4
96
+ with:
97
+ name: dev-package-distributions
98
+ path: dist/
99
+
100
+ publish-dev:
101
+ name: Publish dev build to PyPI
102
+ needs: build
103
+ if: needs.build.outputs.should-publish == 'true'
104
+ runs-on: ubuntu-latest
105
+ environment:
106
+ name: pypi
107
+ url: https://pypi.org/p/codeplain
108
+ permissions:
109
+ # Mint a short-lived OIDC token so PyPI Trusted Publishing can
110
+ # authenticate this run — no long-lived API token needed.
111
+ id-token: write
112
+
113
+ env:
114
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
115
+
116
+ steps:
117
+ - name: Download distribution packages
118
+ uses: actions/download-artifact@v4
119
+ with:
120
+ name: dev-package-distributions
121
+ path: dist/
122
+
123
+ - name: Publish to PyPI
124
+ uses: pypa/gh-action-pypi-publish@release/v1
125
+ with:
126
+ # PyPI uploads are immutable, so a re-run of an already-published
127
+ # version should be a no-op, not a red build.
128
+ skip-existing: true
129
+
130
+ - name: Notify Slack (success)
131
+ if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
132
+ env:
133
+ VERSION: ${{ needs.build.outputs.version }}
134
+ run: |
135
+ # Spell out the --pre install: a plain "pip install codeplain" will
136
+ # NOT pick this up, which otherwise reads as a broken publish.
137
+ TEXT="*Codeplain Client*: dev build \`$VERSION\` published to PyPI :test_tube:. Normal installs are unaffected — try it with \`pip install --pre codeplain==$VERSION\`. Pre-release builds talk to \`api.test.codeplain.ai\` by default."
138
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
139
+ -H 'Content-type: application/json' \
140
+ --data "$(jq -n --arg t "$TEXT" '{text:$t}')"
141
+
142
+ - name: Notify Slack (failure)
143
+ if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
144
+ run: |
145
+ curl -s -X POST "$SLACK_WEBHOOK_URL" \
146
+ -H 'Content-type: application/json' \
147
+ --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,8 +14,11 @@ 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
- - uses: actions/checkout@v4
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
22
 
20
23
  - name: Upload install scripts to R2
21
24
  env:
@@ -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
+