codeplain 0.3.9__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 (269) 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.9 → 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.9 → 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.9 → codeplain-0.3.10}/.github/workflows/publish-install-script.yml +1 -1
  8. {codeplain-0.3.9 → codeplain-0.3.10}/.github/workflows/publish-to-pypi.yml +60 -5
  9. {codeplain-0.3.9 → codeplain-0.3.10}/CLAUDE.md +4 -4
  10. codeplain-0.3.10/CONTRIBUTING.md +137 -0
  11. {codeplain-0.3.9 → codeplain-0.3.10}/PKG-INFO +36 -8
  12. {codeplain-0.3.9 → codeplain-0.3.10}/README.md +31 -3
  13. {codeplain-0.3.9 → codeplain-0.3.10}/codeplain_REST_api.py +6 -14
  14. {codeplain-0.3.9 → codeplain-0.3.10}/concept_utils.py +6 -0
  15. codeplain-0.3.10/conformance_fix_journal.py +207 -0
  16. {codeplain-0.3.9 → codeplain-0.3.10}/docs/plain2code_cli.md +3 -3
  17. {codeplain-0.3.9 → codeplain-0.3.10}/install/bash/install.sh +41 -0
  18. {codeplain-0.3.9 → codeplain-0.3.10}/install/powershell/examples.ps1 +11 -5
  19. {codeplain-0.3.9 → codeplain-0.3.10}/install/powershell/install.ps1 +131 -19
  20. codeplain-0.3.10/install/powershell/walkthrough.ps1 +174 -0
  21. codeplain-0.3.10/memory_management.py +52 -0
  22. {codeplain-0.3.9 → codeplain-0.3.10}/module_renderer.py +6 -0
  23. {codeplain-0.3.9 → codeplain-0.3.10}/partial_rendering.py +35 -4
  24. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code.py +46 -3
  25. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_arguments.py +7 -4
  26. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_console.py +3 -1
  27. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_exceptions.py +8 -0
  28. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_logger.py +37 -15
  29. {codeplain-0.3.9 → codeplain-0.3.10}/plain_file.py +18 -1
  30. {codeplain-0.3.9 → codeplain-0.3.10}/plain_modules.py +197 -7
  31. {codeplain-0.3.9 → codeplain-0.3.10}/pyproject.toml +3 -3
  32. codeplain-0.3.10/render_machine/actions/distill_conformance_test_memory.py +56 -0
  33. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/fix_conformance_test.py +58 -29
  34. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/prepare_repositories.py +13 -0
  35. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/run_conformance_tests.py +5 -11
  36. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/conformance_tests.py +40 -3
  37. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/implementation_code_helpers.py +5 -1
  38. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/render_context.py +13 -1
  39. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/render_types.py +0 -4
  40. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/state_machine_config.py +10 -1
  41. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/states.py +1 -0
  42. {codeplain-0.3.9 → codeplain-0.3.10}/requirements.txt +3 -3
  43. {codeplain-0.3.9 → codeplain-0.3.10}/system_config.py +35 -0
  44. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_cli_output.py +13 -0
  45. codeplain-0.3.10/tests/test_conformance_fix_journal.py +259 -0
  46. codeplain-0.3.10/tests/test_distill_conformance_test_memory.py +145 -0
  47. codeplain-0.3.10/tests/test_dry_run_link_validation.py +60 -0
  48. codeplain-0.3.10/tests/test_headless_logging.py +177 -0
  49. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plain_modules.py +267 -1
  50. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plainfileparser.py +41 -4
  51. codeplain-0.3.10/tests/test_prepare_repositories_layout.py +315 -0
  52. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_system_config.py +37 -0
  53. {codeplain-0.3.9 → codeplain-0.3.10}/tui/plain_module_render_choice_tui.py +25 -8
  54. {codeplain-0.3.9 → codeplain-0.3.10}/tui/state_handlers.py +7 -1
  55. codeplain-0.3.9/.github/dependabot.yml +0 -11
  56. codeplain-0.3.9/.github/workflows/e2e.yml +0 -62
  57. codeplain-0.3.9/install/powershell/walkthrough.ps1 +0 -161
  58. codeplain-0.3.9/memory_management.py +0 -132
  59. codeplain-0.3.9/tests/test_prepare_repositories_layout.py +0 -119
  60. {codeplain-0.3.9 → codeplain-0.3.10}/.claude/settings.json +0 -0
  61. {codeplain-0.3.9 → codeplain-0.3.10}/.flake8 +0 -0
  62. {codeplain-0.3.9 → codeplain-0.3.10}/.gitignore +0 -0
  63. {codeplain-0.3.9 → codeplain-0.3.10}/.vscode/launch.json +0 -0
  64. {codeplain-0.3.9 → codeplain-0.3.10}/.vscode/settings.json +0 -0
  65. {codeplain-0.3.9 → codeplain-0.3.10}/LICENSE +0 -0
  66. {codeplain-0.3.9 → codeplain-0.3.10}/change_detection.py +0 -0
  67. {codeplain-0.3.9 → codeplain-0.3.10}/cli_output/__init__.py +0 -0
  68. {codeplain-0.3.9 → codeplain-0.3.10}/cli_output/dry_run.py +0 -0
  69. {codeplain-0.3.9 → codeplain-0.3.10}/cli_output/render_summary.py +0 -0
  70. {codeplain-0.3.9 → codeplain-0.3.10}/cli_output/status.py +0 -0
  71. {codeplain-0.3.9 → codeplain-0.3.10}/config/__init__.py +0 -0
  72. {codeplain-0.3.9 → codeplain-0.3.10}/config/system_config.yaml +0 -0
  73. {codeplain-0.3.9 → codeplain-0.3.10}/diff_utils.py +0 -0
  74. {codeplain-0.3.9 → codeplain-0.3.10}/docs/generate_cli.py +0 -0
  75. {codeplain-0.3.9 → codeplain-0.3.10}/docs/starting_a_plain_project_from_scratch.md +0 -0
  76. {codeplain-0.3.9 → codeplain-0.3.10}/event_bus.py +0 -0
  77. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_golang/config.yaml +0 -0
  78. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  79. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  80. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_golang/run.sh +0 -0
  81. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_python/config.yaml +0 -0
  82. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  83. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  84. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_python/run.sh +0 -0
  85. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/config.yaml +0 -0
  86. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  87. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  88. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  89. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  90. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  91. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  92. {codeplain-0.3.9 → codeplain-0.3.10}/examples/example_hello_world_react/run.sh +0 -0
  93. {codeplain-0.3.9 → codeplain-0.3.10}/examples/run.sh +0 -0
  94. {codeplain-0.3.9 → codeplain-0.3.10}/file_utils.py +0 -0
  95. {codeplain-0.3.9 → codeplain-0.3.10}/git_utils.py +0 -0
  96. {codeplain-0.3.9 → codeplain-0.3.10}/install/bash/examples.sh +0 -0
  97. {codeplain-0.3.9 → codeplain-0.3.10}/install/bash/walkthrough.sh +0 -0
  98. {codeplain-0.3.9 → codeplain-0.3.10}/metadata_utils.py +0 -0
  99. {codeplain-0.3.9 → codeplain-0.3.10}/path_resolution.py +0 -0
  100. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_cli.md +0 -0
  101. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_events.py +0 -0
  102. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_nodes.py +0 -0
  103. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_read_config.py +0 -0
  104. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_state.py +0 -0
  105. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_telemetry.py +0 -0
  106. {codeplain-0.3.9 → codeplain-0.3.10}/plain2code_utils.py +0 -0
  107. {codeplain-0.3.9 → codeplain-0.3.10}/plain_spec.py +0 -0
  108. {codeplain-0.3.9 → codeplain-0.3.10}/pytest.ini +0 -0
  109. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/__init__.py +0 -0
  110. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  111. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/base_action.py +0 -0
  112. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  113. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  114. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/create_dist.py +0 -0
  115. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/exit_with_error.py +0 -0
  116. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/finish_functional_requirement.py +0 -0
  117. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/fix_unit_tests.py +0 -0
  118. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/prepare_testing_environment.py +0 -0
  119. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/refactor_code.py +0 -0
  120. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/render_conformance_tests.py +0 -0
  121. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/render_functional_requirement.py +0 -0
  122. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/run_unit_tests.py +0 -0
  123. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/actions/summarize_conformance_tests.py +0 -0
  124. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/code_renderer.py +0 -0
  125. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/render_utils.py +0 -0
  126. {codeplain-0.3.9 → codeplain-0.3.10}/render_machine/triggers.py +0 -0
  127. {codeplain-0.3.9 → codeplain-0.3.10}/resources/codeplain_overview.png +0 -0
  128. {codeplain-0.3.9 → codeplain-0.3.10}/resources/plain_example.png +0 -0
  129. {codeplain-0.3.9 → codeplain-0.3.10}/standard_template_library/golang-console-app-template.plain +0 -0
  130. {codeplain-0.3.9 → codeplain-0.3.10}/standard_template_library/python-console-app-template.plain +0 -0
  131. {codeplain-0.3.9 → codeplain-0.3.10}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  132. {codeplain-0.3.9 → codeplain-0.3.10}/standard_template_library/typescript-react-app-template.plain +0 -0
  133. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  134. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  135. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  136. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_golang.sh +0 -0
  137. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  138. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_conformance_tests_python.sh +0 -0
  139. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_flutter.ps1 +0 -0
  140. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_flutter.sh +0 -0
  141. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_golang.ps1 +0 -0
  142. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_golang.sh +0 -0
  143. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_python.ps1 +0 -0
  144. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_python.sh +0 -0
  145. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_react.ps1 +0 -0
  146. {codeplain-0.3.9 → codeplain-0.3.10}/test_scripts/run_unittests_react.sh +0 -0
  147. {codeplain-0.3.9 → codeplain-0.3.10}/tests/__init__.py +0 -0
  148. {codeplain-0.3.9 → codeplain-0.3.10}/tests/conftest.py +0 -0
  149. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
  150. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
  151. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/circular_imports_1.plain +0 -0
  152. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/circular_imports_2.plain +0 -0
  153. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/circular_imports_main.plain +0 -0
  154. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/diamond_import_1.plain +0 -0
  155. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/diamond_import_2.plain +0 -0
  156. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/diamond_import_common.plain +0 -0
  157. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/diamond_imports_main.plain +0 -0
  158. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/import_with_functionalities.plain +0 -0
  159. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
  160. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/imports/non_existent_import.plain +0 -0
  161. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_code_var.plain +0 -0
  162. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_implement.plain +0 -0
  163. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  164. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_middle.plain +0 -0
  165. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_root.plain +0 -0
  166. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/partial_rendering/pr_solo.plain +0 -0
  167. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
  168. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  169. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
  170. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  171. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  172. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
  173. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  174. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  175. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
  176. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  177. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  178. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  179. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  180. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  181. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  182. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  183. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  184. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  185. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  186. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  187. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  188. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  189. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  190. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  191. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  192. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  193. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  194. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  195. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  196. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  197. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  198. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  199. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  200. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  201. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  202. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts.plain +0 -0
  203. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  204. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  205. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  206. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  207. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  208. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  209. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  210. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  211. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/topological_sort.plain +0 -0
  212. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  213. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/circular_requires_main.plain +0 -0
  214. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/circular_requires_sub.plain +0 -0
  215. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/diamond_requires_1.plain +0 -0
  216. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/diamond_requires_2.plain +0 -0
  217. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/diamond_requires_common.plain +0 -0
  218. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/diamond_requires_main.plain +0 -0
  219. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/independent_requires_1.plain +0 -0
  220. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/independent_requires_2.plain +0 -0
  221. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/independent_requires_main.plain +0 -0
  222. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/non_existent_require.plain +0 -0
  223. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/normal_requires_1.plain +0 -0
  224. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/normal_requires_2.plain +0 -0
  225. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/normal_requires_common.plain +0 -0
  226. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/requires/normal_requires_main.plain +0 -0
  227. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/sample_base64_image.txt +0 -0
  228. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/simple.plain +0 -0
  229. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/block_level_include.plain +0 -0
  230. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/code_variables.plain +0 -0
  231. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/header.plain +0 -0
  232. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/implement.plain +0 -0
  233. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/implement_2.plain +0 -0
  234. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/template_include.plain +0 -0
  235. {codeplain-0.3.9 → codeplain-0.3.10}/tests/data/templates/test_hardest_problem.plain +0 -0
  236. {codeplain-0.3.9 → codeplain-0.3.10}/tests/e2e/Dockerfile +0 -0
  237. {codeplain-0.3.9 → codeplain-0.3.10}/tests/e2e/conftest.py +0 -0
  238. {codeplain-0.3.9 → codeplain-0.3.10}/tests/e2e/test_hello_world_python.py +0 -0
  239. {codeplain-0.3.9 → codeplain-0.3.10}/tests/e2e/test_hello_world_python_windows.py +0 -0
  240. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_arg_provenance.py +0 -0
  241. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_change_detection.py +0 -0
  242. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_console_log_styles.py +0 -0
  243. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_file_utils.py +0 -0
  244. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_folder_path_resolution.py +0 -0
  245. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_git_utils.py +0 -0
  246. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_imports.py +0 -0
  247. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_log_file_name_resolution.py +0 -0
  248. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_logging_config_path_resolution.py +0 -0
  249. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_partial_rendering.py +0 -0
  250. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_path_resolution.py +0 -0
  251. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plain2code.py +0 -0
  252. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plain2code_state.py +0 -0
  253. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plain2code_utils.py +0 -0
  254. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plainfile.py +0 -0
  255. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_plainspec.py +0 -0
  256. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_requires.py +0 -0
  257. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_resolve_config_file.py +0 -0
  258. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_script_path_resolution.py +0 -0
  259. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_telemetry.py +0 -0
  260. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_tui_usage.py +0 -0
  261. {codeplain-0.3.9 → codeplain-0.3.10}/tests/test_usage_summary.py +0 -0
  262. {codeplain-0.3.9 → codeplain-0.3.10}/tui/__init__.py +0 -0
  263. {codeplain-0.3.9 → codeplain-0.3.10}/tui/components.py +0 -0
  264. {codeplain-0.3.9 → codeplain-0.3.10}/tui/models.py +0 -0
  265. {codeplain-0.3.9 → codeplain-0.3.10}/tui/plain2code_tui.py +0 -0
  266. {codeplain-0.3.9 → codeplain-0.3.10}/tui/spinner.py +0 -0
  267. {codeplain-0.3.9 → codeplain-0.3.10}/tui/styles.css +0 -0
  268. {codeplain-0.3.9 → codeplain-0.3.10}/tui/widget_helpers.py +0 -0
  269. {codeplain-0.3.9 → 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>.\"}"
@@ -18,7 +18,7 @@ jobs:
18
18
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
19
19
 
20
20
  steps:
21
- - uses: actions/checkout@v4
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
22
 
23
23
  - name: Upload install scripts to R2
24
24
  env:
@@ -19,7 +19,7 @@ jobs:
19
19
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
20
20
 
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  # hatch-vcs derives the version from git tags, so we need full history.
25
25
  fetch-depth: 0
@@ -46,7 +46,7 @@ jobs:
46
46
  ls -l dist/
47
47
 
48
48
  - name: Store the distribution packages
49
- uses: actions/upload-artifact@v4
49
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
50
50
  with:
51
51
  name: python-package-distributions
52
52
  path: dist/
@@ -81,20 +81,33 @@ jobs:
81
81
 
82
82
  steps:
83
83
  - name: Download distribution packages
84
- uses: actions/download-artifact@v4
84
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
85
85
  with:
86
86
  name: python-package-distributions
87
87
  path: dist/
88
88
 
89
89
  - name: Publish to PyPI
90
- uses: pypa/gh-action-pypi-publish@release/v1
90
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
91
91
 
92
92
  - name: Notify Slack (success)
93
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 }}
94
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
95
108
  curl -s -X POST "$SLACK_WEBHOOK_URL" \
96
109
  -H 'Content-type: application/json' \
97
- --data "{\"text\":\"*Codeplain Client*: \`${{ github.ref_name }}\` published to PyPI :white_check_mark:. Install with \`pip install --upgrade codeplain\`.\"}"
110
+ --data "$(jq -n --arg t "$TEXT" '{text:$t}')"
98
111
 
99
112
  - name: Notify Slack (failure)
100
113
  if: ${{ failure() && env.SLACK_WEBHOOK_URL != '' }}
@@ -102,3 +115,45 @@ jobs:
102
115
  curl -s -X POST "$SLACK_WEBHOOK_URL" \
103
116
  -H 'Content-type: application/json' \
104
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>.\"}"
118
+
119
+ # Release pipelines to be turned on only after the rest of the infrastructure
120
+ # is ready.
121
+ #
122
+ # # Runs only after the package is on PyPI. Kept as its own job so the publish job
123
+ # # keeps its minimal permissions and no checkout.
124
+ # linear-release:
125
+ # name: Record release in Linear
126
+ # needs: publish-to-pypi
127
+ # runs-on: ubuntu-latest
128
+ #
129
+ # permissions:
130
+ # contents: read
131
+ #
132
+ # env:
133
+ # SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
134
+ #
135
+ # steps:
136
+ # - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
137
+ # with:
138
+ # # The scan needs full history.
139
+ # fetch-depth: 0
140
+ #
141
+ # # Non-fatal: the package is already published.
142
+ # - name: Record release in Linear
143
+ # id: linear
144
+ # continue-on-error: true
145
+ # uses: linear/linear-release-action@0a25abab892a91062ebf42260dbb2ce6277aa205 # v0.16.0
146
+ # with:
147
+ # access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
148
+ # version: ${{ github.ref_name }}
149
+ # # Pin the CLI the action downloads, not just the action.
150
+ # cli_version: v0.16.0
151
+ #
152
+ # # continue-on-error keeps the job green, so this checks the step's own
153
+ # # outcome — `failure()` would never fire.
154
+ # - name: Notify Slack (release not recorded)
155
+ # if: ${{ steps.linear.outcome == 'failure' && env.SLACK_WEBHOOK_URL != '' }}
156
+ # run: |
157
+ # curl -s -X POST "$SLACK_WEBHOOK_URL" \
158
+ # -H 'Content-type: application/json' \
159
+ # --data "{\"text\":\"*Codeplain Client*: \`${{ github.ref_name }}\` is on PyPI, but recording it in Linear FAILED :warning:. 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:**