words2num2 0.2.1__tar.gz → 0.3.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. words2num2-0.3.0.dev1/.github/workflows/aur-publish.yml +104 -0
  2. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.github/workflows/ci.yml +5 -3
  3. words2num2-0.3.0.dev1/.github/workflows/codeql-analysis.yml +38 -0
  4. words2num2-0.3.0.dev1/.github/workflows/e2e-tests.yml +73 -0
  5. words2num2-0.3.0.dev1/.github/workflows/manual-publish.yml +66 -0
  6. words2num2-0.3.0.dev1/.github/workflows/manual-release.yml +81 -0
  7. words2num2-0.3.0.dev1/.github/workflows/pr-size.yml +67 -0
  8. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.github/workflows/publish-pypi.yml +1 -1
  9. words2num2-0.3.0.dev1/.github/workflows/python-publish.yml +61 -0
  10. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.github/workflows/release.yml +2 -2
  11. words2num2-0.3.0.dev1/.github/workflows/scheduled-test.yml +44 -0
  12. words2num2-0.3.0.dev1/CHANGELOG.md +139 -0
  13. words2num2-0.3.0.dev1/CONTRIBUTING.md +123 -0
  14. words2num2-0.3.0.dev1/LOCAL_TESTING.md +173 -0
  15. words2num2-0.3.0.dev1/PKG-INFO +389 -0
  16. words2num2-0.3.0.dev1/README.rst +351 -0
  17. words2num2-0.3.0.dev1/REFERENCE.md +450 -0
  18. words2num2-0.3.0.dev1/packaging/aur/python-words2num2/.SRCINFO +20 -0
  19. words2num2-0.3.0.dev1/packaging/aur/python-words2num2/PKGBUILD +33 -0
  20. words2num2-0.3.0.dev1/packaging/aur/python-words2num2/README.md +88 -0
  21. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/pyproject.toml +3 -3
  22. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/setup.py +2 -2
  23. words2num2-0.3.0.dev1/words2num2/_version.py +3 -0
  24. words2num2-0.3.0.dev1/words2num2.egg-info/PKG-INFO +389 -0
  25. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2.egg-info/SOURCES.txt +14 -0
  26. words2num2-0.2.1/CONTRIBUTING.md +0 -36
  27. words2num2-0.2.1/PKG-INFO +0 -210
  28. words2num2-0.2.1/README.rst +0 -172
  29. words2num2-0.2.1/words2num2/_version.py +0 -3
  30. words2num2-0.2.1/words2num2.egg-info/PKG-INFO +0 -210
  31. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.flake8 +0 -0
  32. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.github/workflows/lint.yml +0 -0
  33. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/.gitignore +0 -0
  34. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/COPYING +0 -0
  35. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/MANIFEST.in +0 -0
  36. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/Makefile +0 -0
  37. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/bin/words2num2 +0 -0
  38. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/setup.cfg +0 -0
  39. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/tests/__init__.py +0 -0
  40. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/tests/test_auto_parse.py +0 -0
  41. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/tests/test_dispatch.py +0 -0
  42. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/tests/test_lang_EN.py +0 -0
  43. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/tests/test_multilang.py +0 -0
  44. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/__init__.py +0 -0
  45. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/__main__.py +0 -0
  46. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/base.py +0 -0
  47. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/compat.py +0 -0
  48. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/converters/__init__.py +0 -0
  49. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/converters/auto.py +0 -0
  50. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/converters/sentence.py +0 -0
  51. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/formats.py +0 -0
  52. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_AF.py +0 -0
  53. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_AM.py +0 -0
  54. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_AR.py +0 -0
  55. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_AS.py +0 -0
  56. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_AZ.py +0 -0
  57. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BA.py +0 -0
  58. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BE.py +0 -0
  59. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BG.py +0 -0
  60. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BN.py +0 -0
  61. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BO.py +0 -0
  62. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BR.py +0 -0
  63. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_BS.py +0 -0
  64. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_CA.py +0 -0
  65. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_CE.py +0 -0
  66. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_CS.py +0 -0
  67. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_CY.py +0 -0
  68. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_DA.py +0 -0
  69. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_DE.py +0 -0
  70. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EL.py +0 -0
  71. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EN.py +0 -0
  72. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EN_IN.py +0 -0
  73. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EN_NG.py +0 -0
  74. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EO.py +0 -0
  75. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES.py +0 -0
  76. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES_CO.py +0 -0
  77. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES_CR.py +0 -0
  78. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES_GT.py +0 -0
  79. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES_NI.py +0 -0
  80. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ES_VE.py +0 -0
  81. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ET.py +0 -0
  82. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_EU.py +0 -0
  83. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FA.py +0 -0
  84. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FI.py +0 -0
  85. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FO.py +0 -0
  86. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FR.py +0 -0
  87. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FR_BE.py +0 -0
  88. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FR_CH.py +0 -0
  89. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_FR_DZ.py +0 -0
  90. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_GL.py +0 -0
  91. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_GU.py +0 -0
  92. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HA.py +0 -0
  93. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HAW.py +0 -0
  94. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HE.py +0 -0
  95. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HI.py +0 -0
  96. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HR.py +0 -0
  97. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HT.py +0 -0
  98. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HU.py +0 -0
  99. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_HY.py +0 -0
  100. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ID.py +0 -0
  101. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_IS.py +0 -0
  102. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_IT.py +0 -0
  103. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_JA.py +0 -0
  104. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_JW.py +0 -0
  105. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KA.py +0 -0
  106. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KK.py +0 -0
  107. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KM.py +0 -0
  108. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KN.py +0 -0
  109. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KO.py +0 -0
  110. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_KZ.py +0 -0
  111. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LA.py +0 -0
  112. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LB.py +0 -0
  113. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LN.py +0 -0
  114. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LO.py +0 -0
  115. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LT.py +0 -0
  116. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_LV.py +0 -0
  117. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MG.py +0 -0
  118. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MI.py +0 -0
  119. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MK.py +0 -0
  120. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ML.py +0 -0
  121. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MN.py +0 -0
  122. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MR.py +0 -0
  123. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MS.py +0 -0
  124. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MT.py +0 -0
  125. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_MY.py +0 -0
  126. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_NE.py +0 -0
  127. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_NL.py +0 -0
  128. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_NN.py +0 -0
  129. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_NO.py +0 -0
  130. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_OC.py +0 -0
  131. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_PA.py +0 -0
  132. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_PL.py +0 -0
  133. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_PS.py +0 -0
  134. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_PT.py +0 -0
  135. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_PT_BR.py +0 -0
  136. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_RO.py +0 -0
  137. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_RU.py +0 -0
  138. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SA.py +0 -0
  139. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SD.py +0 -0
  140. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SI.py +0 -0
  141. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SK.py +0 -0
  142. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SL.py +0 -0
  143. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SN.py +0 -0
  144. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SO.py +0 -0
  145. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SQ.py +0 -0
  146. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SR.py +0 -0
  147. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SU.py +0 -0
  148. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SV.py +0 -0
  149. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_SW.py +0 -0
  150. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TA.py +0 -0
  151. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TE.py +0 -0
  152. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TET.py +0 -0
  153. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TG.py +0 -0
  154. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TH.py +0 -0
  155. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TK.py +0 -0
  156. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TL.py +0 -0
  157. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TR.py +0 -0
  158. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_TT.py +0 -0
  159. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_UK.py +0 -0
  160. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_UR.py +0 -0
  161. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_UZ.py +0 -0
  162. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_VI.py +0 -0
  163. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_WO.py +0 -0
  164. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_YI.py +0 -0
  165. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_YO.py +0 -0
  166. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ZH.py +0 -0
  167. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ZH_CN.py +0 -0
  168. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ZH_HK.py +0 -0
  169. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/lang_ZH_TW.py +0 -0
  170. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2/utils.py +0 -0
  171. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2.egg-info/dependency_links.txt +0 -0
  172. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2.egg-info/entry_points.txt +0 -0
  173. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2.egg-info/requires.txt +0 -0
  174. {words2num2-0.2.1 → words2num2-0.3.0.dev1}/words2num2.egg-info/top_level.txt +0 -0
@@ -0,0 +1,104 @@
1
+ # Auto-publish to the AUR (Arch User Repository) when a new tag lands on PyPI.
2
+ # Triggers on tag push to v* OR via workflow_dispatch.
3
+ #
4
+ # Requires repo secret AUR_SSH_PRIVATE_KEY (the private key whose public
5
+ # half is registered on the maintainer's AUR account).
6
+ name: Publish AUR package
7
+
8
+ on:
9
+ push:
10
+ tags:
11
+ - 'v*'
12
+ workflow_dispatch:
13
+ inputs:
14
+ version:
15
+ description: 'Version to push to AUR (e.g., 0.2.2)'
16
+ required: true
17
+ type: string
18
+
19
+ jobs:
20
+ aur:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: Resolve version
26
+ id: ver
27
+ run: |
28
+ if [ -n "${{ inputs.version }}" ]; then
29
+ echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
30
+ else
31
+ TAG="${GITHUB_REF#refs/tags/v}"
32
+ echo "version=$TAG" >> $GITHUB_OUTPUT
33
+ fi
34
+
35
+ - name: Wait for PyPI sdist to be live
36
+ run: |
37
+ VER="${{ steps.ver.outputs.version }}"
38
+ for i in $(seq 1 60); do
39
+ CODE=$(curl -sL -o /dev/null -w "%{http_code}" \
40
+ "https://files.pythonhosted.org/packages/source/w/words2num2/words2num2-${VER}.tar.gz")
41
+ if [ "$CODE" = "200" ]; then
42
+ echo "PyPI sdist for $VER is live."
43
+ break
44
+ fi
45
+ echo "Waiting for PyPI sdist... ($i/60) (got $CODE)"
46
+ sleep 10
47
+ done
48
+
49
+ - name: Compute sha256 of PyPI sdist
50
+ id: sha
51
+ run: |
52
+ VER="${{ steps.ver.outputs.version }}"
53
+ SHA=$(curl -sL "https://files.pythonhosted.org/packages/source/w/words2num2/words2num2-${VER}.tar.gz" | sha256sum | awk '{print $1}')
54
+ echo "sha=$SHA" >> $GITHUB_OUTPUT
55
+ echo "sha256: $SHA"
56
+
57
+ - name: Update PKGBUILD + .SRCINFO
58
+ run: |
59
+ VER="${{ steps.ver.outputs.version }}"
60
+ SHA="${{ steps.sha.outputs.sha }}"
61
+ cd packaging/aur/python-words2num2
62
+ sed -i -E "s/^pkgver=.*/pkgver=${VER}/" PKGBUILD
63
+ sed -i -E "s/^pkgrel=.*/pkgrel=1/" PKGBUILD
64
+ sed -i -E "s/^sha256sums=\(.*\)/sha256sums=('${SHA}')/" PKGBUILD
65
+ # Regenerate .SRCINFO from the patched PKGBUILD.
66
+ # Use a docker container that has makepkg available.
67
+ docker run --rm -v "$PWD":/pkg -w /pkg archlinux:base-devel \
68
+ bash -lc "useradd -m b && chown -R b:b /pkg && su b -c 'makepkg --printsrcinfo > .SRCINFO'"
69
+ cat PKGBUILD
70
+ echo "---"
71
+ cat .SRCINFO
72
+
73
+ - name: Push to AUR
74
+ env:
75
+ AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
76
+ run: |
77
+ if [ -z "$AUR_SSH_PRIVATE_KEY" ]; then
78
+ echo "::warning::AUR_SSH_PRIVATE_KEY secret not set; skipping push."
79
+ exit 0
80
+ fi
81
+ mkdir -p ~/.ssh
82
+ echo "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
83
+ chmod 600 ~/.ssh/aur
84
+ ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
85
+ cat > ~/.ssh/config <<EOF
86
+ Host aur.archlinux.org
87
+ IdentityFile ~/.ssh/aur
88
+ User aur
89
+ EOF
90
+
91
+ VER="${{ steps.ver.outputs.version }}"
92
+ git clone ssh://aur@aur.archlinux.org/python-words2num2.git /tmp/aur || true
93
+ cp packaging/aur/python-words2num2/PKGBUILD /tmp/aur/
94
+ cp packaging/aur/python-words2num2/.SRCINFO /tmp/aur/
95
+ cd /tmp/aur
96
+ git config user.email "jlqueguiner@gladia.io"
97
+ git config user.name "Jean-Louis Queguiner"
98
+ git add PKGBUILD .SRCINFO
99
+ if git diff --cached --quiet; then
100
+ echo "No AUR changes."
101
+ exit 0
102
+ fi
103
+ git commit -m "Bump to ${VER}"
104
+ git push origin master
@@ -6,8 +6,9 @@ jobs:
6
6
  build:
7
7
  runs-on: ubuntu-latest
8
8
  strategy:
9
+ fail-fast: false
9
10
  matrix:
10
- python-version: [3.8, 3.9, '3.10', '3.11', '3.12', '3.13']
11
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
11
12
 
12
13
  steps:
13
14
  - uses: actions/checkout@v4
@@ -18,6 +19,7 @@ jobs:
18
19
  uses: actions/setup-python@v5
19
20
  with:
20
21
  python-version: ${{ matrix.python-version }}
22
+ allow-prereleases: true
21
23
 
22
24
  - name: Install dependencies
23
25
  run: |
@@ -30,14 +32,14 @@ jobs:
30
32
  pytest tests/ -v --cov=words2num2 --cov-report=term-missing
31
33
 
32
34
  - name: Build package
33
- if: matrix.python-version == '3.11'
35
+ if: matrix.python-version == '3.13'
34
36
  run: |
35
37
  pip install build
36
38
  python -m build
37
39
  ls -la dist/
38
40
 
39
41
  - name: Upload build artifacts
40
- if: matrix.python-version == '3.11'
42
+ if: matrix.python-version == '3.13'
41
43
  uses: actions/upload-artifact@v4
42
44
  with:
43
45
  name: python-package-distributions
@@ -0,0 +1,38 @@
1
+ name: "CodeQL"
2
+
3
+ on:
4
+ push:
5
+ branches: [ master, main ]
6
+ pull_request:
7
+ branches: [ master, main ]
8
+ schedule:
9
+ - cron: '45 23 * * 5'
10
+
11
+ jobs:
12
+ analyze:
13
+ name: Analyze
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ actions: read
17
+ contents: read
18
+ security-events: write
19
+
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ language: [ 'python' ]
24
+
25
+ steps:
26
+ - name: Checkout repository
27
+ uses: actions/checkout@v4
28
+
29
+ - name: Initialize CodeQL
30
+ uses: github/codeql-action/init@v3
31
+ with:
32
+ languages: ${{ matrix.language }}
33
+
34
+ - name: Autobuild
35
+ uses: github/codeql-action/autobuild@v3
36
+
37
+ - name: Perform CodeQL Analysis
38
+ uses: github/codeql-action/analyze@v3
@@ -0,0 +1,73 @@
1
+ name: E2E Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ master, main, develop ]
6
+ paths:
7
+ - 'words2num2/**'
8
+ - 'tests/**'
9
+ - '.github/workflows/e2e-tests.yml'
10
+ pull_request:
11
+ branches: [ master, main ]
12
+ paths:
13
+ - 'words2num2/**'
14
+ - 'tests/**'
15
+ schedule:
16
+ - cron: '0 2 * * *'
17
+ workflow_dispatch:
18
+
19
+ jobs:
20
+ test:
21
+ runs-on: ${{ matrix.os }}
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ os: [ubuntu-latest, macos-latest, windows-latest]
26
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
27
+ include:
28
+ - os: ubuntu-latest
29
+ python-version: 'pypy-3.10'
30
+
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - name: Set up Python ${{ matrix.python-version }}
35
+ uses: actions/setup-python@v5
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+ allow-prereleases: true
39
+ cache: 'pip'
40
+
41
+ - name: Install dependencies
42
+ run: |
43
+ python -m pip install --upgrade pip
44
+ pip install pytest pytest-cov
45
+ pip install -e .
46
+
47
+ - name: Run E2E suite
48
+ run: pytest tests/ -v --tb=short
49
+ continue-on-error: ${{ startsWith(matrix.python-version, 'pypy') }}
50
+
51
+ - name: Upload test results
52
+ if: always()
53
+ uses: actions/upload-artifact@v4
54
+ with:
55
+ name: e2e-results-${{ matrix.os }}-${{ matrix.python-version }}
56
+ path: |
57
+ *.log
58
+ test-results/
59
+ retention-days: 30
60
+
61
+ summary:
62
+ needs: test
63
+ runs-on: ubuntu-latest
64
+ if: always()
65
+ steps:
66
+ - name: Create summary
67
+ run: |
68
+ echo "# E2E Test Results Summary" >> $GITHUB_STEP_SUMMARY
69
+ echo "" >> $GITHUB_STEP_SUMMARY
70
+ echo "## Test Configuration" >> $GITHUB_STEP_SUMMARY
71
+ echo "- Trigger: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
72
+ echo "- Branch: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
73
+ echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,66 @@
1
+ # Manual workflow to publish to PyPI without going through a tag.
2
+ # Useful for hotfixes or test-PyPI dry runs.
3
+ name: Manual PyPI Publish
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: 'Version to publish (e.g., 0.2.2)'
10
+ required: true
11
+ type: string
12
+ test_pypi:
13
+ description: 'Publish to Test PyPI first?'
14
+ required: false
15
+ type: boolean
16
+ default: true
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ publish:
23
+ runs-on: ubuntu-latest
24
+
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: '3.13'
34
+
35
+ - name: Install dependencies
36
+ run: |
37
+ python -m pip install --upgrade pip
38
+ pip install build twine
39
+
40
+ - name: Build package
41
+ env:
42
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ inputs.version }}
43
+ run: |
44
+ python -m build
45
+ ls -la dist/
46
+
47
+ - name: Check distribution
48
+ run: twine check dist/*
49
+
50
+ - name: Publish to Test PyPI
51
+ if: inputs.test_pypi
52
+ env:
53
+ TWINE_USERNAME: __token__
54
+ TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
55
+ run: |
56
+ twine upload --repository testpypi dist/* --verbose
57
+ echo "Install with: pip install --index-url https://test.pypi.org/simple/ words2num2==${{ inputs.version }}"
58
+
59
+ - name: Publish to PyPI
60
+ if: success()
61
+ env:
62
+ TWINE_USERNAME: __token__
63
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
64
+ run: |
65
+ twine upload dist/* --verbose
66
+ echo "Install with: pip install words2num2==${{ inputs.version }}"
@@ -0,0 +1,81 @@
1
+ name: Manual Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: 'Version number (e.g., 0.3.0)'
8
+ required: true
9
+ type: string
10
+ prerelease:
11
+ description: 'Pre-release?'
12
+ required: false
13
+ type: boolean
14
+ default: false
15
+
16
+ jobs:
17
+ create-release:
18
+ runs-on: ubuntu-latest
19
+ permissions:
20
+ contents: write
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+ token: ${{ secrets.GITHUB_TOKEN }}
27
+
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v5
30
+ with:
31
+ python-version: '3.13'
32
+
33
+ - name: Install dependencies
34
+ run: |
35
+ python -m pip install --upgrade pip
36
+ pip install build setuptools wheel setuptools_scm pytest pytest-cov twine
37
+ pip install -e .
38
+
39
+ - name: Run tests
40
+ run: pytest tests/ -v --tb=short
41
+
42
+ - name: Create and push tag
43
+ run: |
44
+ git config user.name "GitHub Actions"
45
+ git config user.email "actions@github.com"
46
+ git tag -a "v${{ inputs.version }}" -m "Release v${{ inputs.version }}"
47
+ git push origin "v${{ inputs.version }}"
48
+
49
+ - name: Build distribution
50
+ env:
51
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ inputs.version }}
52
+ run: |
53
+ python -m build
54
+ ls -la dist/
55
+ twine check dist/*
56
+
57
+ - name: Create GitHub Release
58
+ uses: softprops/action-gh-release@v2
59
+ with:
60
+ tag_name: v${{ inputs.version }}
61
+ name: Release v${{ inputs.version }}
62
+ draft: false
63
+ prerelease: ${{ inputs.prerelease }}
64
+ files: dist/*
65
+ generate_release_notes: true
66
+ body: |
67
+ ## words2num2 v${{ inputs.version }}
68
+
69
+ ### Installation
70
+ ```bash
71
+ pip install words2num2==${{ inputs.version }}
72
+ ```
73
+
74
+ See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md)
75
+ for the full list of changes.
76
+
77
+ - name: Upload artifacts
78
+ uses: actions/upload-artifact@v4
79
+ with:
80
+ name: python-package-distributions
81
+ path: dist/
@@ -0,0 +1,67 @@
1
+ name: Pull Request Size Labeler
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+
7
+ jobs:
8
+ label:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Get PR Size
15
+ uses: actions/github-script@v7
16
+ with:
17
+ script: |
18
+ const { data: pr } = await github.rest.pulls.get({
19
+ owner: context.repo.owner,
20
+ repo: context.repo.repo,
21
+ pull_number: context.issue.number
22
+ });
23
+
24
+ const size = pr.additions + pr.deletions;
25
+ let label = '';
26
+
27
+ if (size < 10) {
28
+ label = 'size/XS';
29
+ } else if (size < 30) {
30
+ label = 'size/S';
31
+ } else if (size < 100) {
32
+ label = 'size/M';
33
+ } else if (size < 500) {
34
+ label = 'size/L';
35
+ } else if (size < 1000) {
36
+ label = 'size/XL';
37
+ } else {
38
+ label = 'size/XXL';
39
+ }
40
+
41
+ // Remove existing size labels
42
+ const labels = await github.rest.issues.listLabelsOnIssue({
43
+ owner: context.repo.owner,
44
+ repo: context.repo.repo,
45
+ issue_number: context.issue.number
46
+ });
47
+
48
+ const sizeLabels = labels.data
49
+ .filter(label => label.name.startsWith('size/'))
50
+ .map(label => label.name);
51
+
52
+ for (const oldLabel of sizeLabels) {
53
+ await github.rest.issues.removeLabel({
54
+ owner: context.repo.owner,
55
+ repo: context.repo.repo,
56
+ issue_number: context.issue.number,
57
+ name: oldLabel
58
+ }).catch(() => {});
59
+ }
60
+
61
+ // Add new size label
62
+ await github.rest.issues.addLabels({
63
+ owner: context.repo.owner,
64
+ repo: context.repo.repo,
65
+ issue_number: context.issue.number,
66
+ labels: [label]
67
+ }).catch(() => {});
@@ -25,7 +25,7 @@ jobs:
25
25
  - name: Set up Python
26
26
  uses: actions/setup-python@v5
27
27
  with:
28
- python-version: '3.11'
28
+ python-version: '3.13'
29
29
 
30
30
  - name: Install dependencies
31
31
  run: |
@@ -0,0 +1,61 @@
1
+ # Auto-publish hook: when CI succeeds on main, build the package and
2
+ # publish to PyPI ONLY if the version isn't already there. Tag-based
3
+ # releases via release.yml are still the primary path; this workflow is
4
+ # a safety net for one-off pushes that bumped the version without a tag.
5
+ name: Upload Python Package
6
+
7
+ on:
8
+ workflow_run:
9
+ workflows: ["CI"]
10
+ types: [completed]
11
+ branches: [main]
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ deploy:
18
+ runs-on: ubuntu-latest
19
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Set up Python
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version: '3.13'
30
+
31
+ - name: Install dependencies
32
+ run: |
33
+ python -m pip install --upgrade pip
34
+ pip install build twine setuptools_scm
35
+
36
+ - name: Detect current version (from setuptools_scm)
37
+ id: ver
38
+ run: |
39
+ VER=$(python -c "from setuptools_scm import get_version; print(get_version())")
40
+ echo "version=$VER" >> $GITHUB_OUTPUT
41
+ echo "Detected version: $VER"
42
+
43
+ - name: Check if already on PyPI
44
+ id: check
45
+ run: |
46
+ if pip index versions words2num2 2>/dev/null | grep -q "${{ steps.ver.outputs.version }}"; then
47
+ echo "exists=true" >> $GITHUB_OUTPUT
48
+ else
49
+ echo "exists=false" >> $GITHUB_OUTPUT
50
+ fi
51
+
52
+ - name: Build package
53
+ if: steps.check.outputs.exists == 'false'
54
+ run: python -m build
55
+
56
+ - name: Publish to PyPI
57
+ if: steps.check.outputs.exists == 'false'
58
+ env:
59
+ TWINE_USERNAME: __token__
60
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
61
+ run: twine upload dist/* --verbose
@@ -26,7 +26,7 @@ jobs:
26
26
  - name: Set up Python
27
27
  uses: actions/setup-python@v5
28
28
  with:
29
- python-version: '3.11'
29
+ python-version: '3.13'
30
30
 
31
31
  - name: Install build dependencies
32
32
  run: |
@@ -60,7 +60,7 @@ jobs:
60
60
  - name: Set up Python
61
61
  uses: actions/setup-python@v5
62
62
  with:
63
- python-version: '3.11'
63
+ python-version: '3.13'
64
64
 
65
65
  - name: Download artifacts
66
66
  uses: actions/download-artifact@v4
@@ -0,0 +1,44 @@
1
+ name: Scheduled Tests
2
+
3
+ on:
4
+ schedule:
5
+ # Run tests every day at 2 AM UTC
6
+ - cron: '0 2 * * *'
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ test-all-versions:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, windows-latest, macos-latest]
16
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ allow-prereleases: true
26
+
27
+ - name: Install dependencies
28
+ run: |
29
+ python -m pip install --upgrade pip
30
+ pip install pytest pytest-cov
31
+ pip install -e .
32
+
33
+ - name: Run tests
34
+ run: pytest tests/ -v --cov=words2num2 --cov-report=term-missing
35
+
36
+ - name: Upload test results
37
+ if: always()
38
+ uses: actions/upload-artifact@v4
39
+ with:
40
+ name: test-results-${{ matrix.os }}-${{ matrix.python-version }}
41
+ path: |
42
+ .coverage
43
+ htmlcov/
44
+ retention-days: 30