words2num2 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- words2num2-0.2.2/.github/workflows/aur-publish.yml +104 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/.github/workflows/ci.yml +5 -3
- words2num2-0.2.2/.github/workflows/codeql-analysis.yml +38 -0
- words2num2-0.2.2/.github/workflows/e2e-tests.yml +73 -0
- words2num2-0.2.2/.github/workflows/manual-publish.yml +66 -0
- words2num2-0.2.2/.github/workflows/manual-release.yml +81 -0
- words2num2-0.2.2/.github/workflows/pr-size.yml +67 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/.github/workflows/publish-pypi.yml +1 -1
- words2num2-0.2.2/.github/workflows/python-publish.yml +61 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/.github/workflows/release.yml +2 -2
- words2num2-0.2.2/.github/workflows/scheduled-test.yml +44 -0
- words2num2-0.2.2/CHANGELOG.md +139 -0
- words2num2-0.2.2/CONTRIBUTING.md +123 -0
- words2num2-0.2.2/LOCAL_TESTING.md +173 -0
- words2num2-0.2.2/PKG-INFO +389 -0
- words2num2-0.2.2/README.rst +351 -0
- words2num2-0.2.2/REFERENCE.md +450 -0
- words2num2-0.2.2/packaging/aur/python-words2num2/.SRCINFO +20 -0
- words2num2-0.2.2/packaging/aur/python-words2num2/PKGBUILD +33 -0
- words2num2-0.2.2/packaging/aur/python-words2num2/README.md +88 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/pyproject.toml +3 -3
- {words2num2-0.2.0 → words2num2-0.2.2}/setup.py +2 -2
- {words2num2-0.2.0 → words2num2-0.2.2}/tests/test_auto_parse.py +47 -0
- words2num2-0.2.2/words2num2/_version.py +3 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/converters/auto.py +55 -5
- words2num2-0.2.2/words2num2.egg-info/PKG-INFO +389 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2.egg-info/SOURCES.txt +14 -0
- words2num2-0.2.0/CONTRIBUTING.md +0 -36
- words2num2-0.2.0/PKG-INFO +0 -210
- words2num2-0.2.0/README.rst +0 -172
- words2num2-0.2.0/words2num2/_version.py +0 -3
- words2num2-0.2.0/words2num2.egg-info/PKG-INFO +0 -210
- {words2num2-0.2.0 → words2num2-0.2.2}/.flake8 +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/.github/workflows/lint.yml +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/.gitignore +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/COPYING +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/MANIFEST.in +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/Makefile +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/bin/words2num2 +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/setup.cfg +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/tests/__init__.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/tests/test_dispatch.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/tests/test_lang_EN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/tests/test_multilang.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/__init__.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/__main__.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/base.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/compat.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/converters/__init__.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/converters/sentence.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/formats.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_AF.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_AM.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_AR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_AS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_AZ.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BG.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_BS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_CA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_CE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_CS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_CY.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_DA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_DE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EN_IN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EN_NG.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES_CO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES_CR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES_GT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES_NI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ES_VE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ET.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_EU.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FR_BE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FR_CH.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_FR_DZ.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_GL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_GU.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HAW.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HU.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_HY.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ID.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_IS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_IT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_JA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_JW.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KM.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_KZ.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LB.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_LV.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MG.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ML.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_MY.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_NE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_NL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_NN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_NO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_OC.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_PA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_PL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_PS.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_PT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_PT_BR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_RO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_RU.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SD.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SQ.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SU.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SV.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_SW.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TA.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TE.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TET.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TG.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TH.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TL.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_TT.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_UK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_UR.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_UZ.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_VI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_WO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_YI.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_YO.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ZH.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ZH_CN.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ZH_HK.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/lang_ZH_TW.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2/utils.py +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2.egg-info/dependency_links.txt +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2.egg-info/entry_points.txt +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/words2num2.egg-info/requires.txt +0 -0
- {words2num2-0.2.0 → words2num2-0.2.2}/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 -s -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)"
|
|
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.
|
|
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.
|
|
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.
|
|
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(() => {});
|
|
@@ -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.
|
|
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.
|
|
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
|