fyre-toolkit 0.1.13__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.
- fyre_toolkit-0.1.13/.editorconfig +17 -0
- fyre_toolkit-0.1.13/.gitee/ISSUE_TEMPLATE.zh-CN.md +13 -0
- fyre_toolkit-0.1.13/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +12 -0
- fyre_toolkit-0.1.13/.github/ISSUE_TEMPLATE/config.yaml +1 -0
- fyre_toolkit-0.1.13/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
- fyre_toolkit-0.1.13/.github/ISSUE_TEMPLATE/issue_report.yml +54 -0
- fyre_toolkit-0.1.13/.github/workflows/test.yml +131 -0
- fyre_toolkit-0.1.13/.gitignore +156 -0
- fyre_toolkit-0.1.13/.vscode/settings.json +7 -0
- fyre_toolkit-0.1.13/AGENTS.md +129 -0
- fyre_toolkit-0.1.13/Jenkinsfile +124 -0
- fyre_toolkit-0.1.13/LICENSE +201 -0
- fyre_toolkit-0.1.13/PKG-INFO +96 -0
- fyre_toolkit-0.1.13/README.en.md +105 -0
- fyre_toolkit-0.1.13/README.md +82 -0
- fyre_toolkit-0.1.13/deployment_manifest.txt +109 -0
- fyre_toolkit-0.1.13/examples/generate_result.py +35 -0
- fyre_toolkit-0.1.13/examples/sample_test_suite.yaml +37 -0
- fyre_toolkit-0.1.13/examples/test_example.py +163 -0
- fyre_toolkit-0.1.13/pyproject.toml +92 -0
- fyre_toolkit-0.1.13/resources/kd-test/db-oodbapi.result +16 -0
- fyre_toolkit-0.1.13/resources/kd-test/rtdbc-middate.result +11 -0
- fyre_toolkit-0.1.13/resources/kd-test/rtdbc-midmmi.result +9 -0
- fyre_toolkit-0.1.13/resources/kd-test/scada.result +11 -0
- fyre_toolkit-0.1.13/resources/kd-test/sjk-download.result +8 -0
- fyre_toolkit-0.1.13/resources/kd-test/sjk-metadata.result +8 -0
- fyre_toolkit-0.1.13/resources/kd-test/sjk-sync.result +8 -0
- fyre_toolkit-0.1.13/resources/kd-test/zx-xtgl.result +27 -0
- fyre_toolkit-0.1.13/resources/multiple_test_case_template.yaml +68 -0
- fyre_toolkit-0.1.13/resources/single_test_case_template.yaml +38 -0
- fyre_toolkit-0.1.13/resources/test_result.xml +25 -0
- fyre_toolkit-0.1.13/resources/test_result_formatted.xml +292 -0
- fyre_toolkit-0.1.13/resources/test_suite_schema.json +143 -0
- fyre_toolkit-0.1.13/resources/test_suite_template.json +87 -0
- fyre_toolkit-0.1.13/src/testkit/__init__.py +20 -0
- fyre_toolkit-0.1.13/src/testkit/aggregator.py +59 -0
- fyre_toolkit-0.1.13/src/testkit/generator.py +431 -0
- fyre_toolkit-0.1.13/src/testkit/parser.py +50 -0
- fyre_toolkit-0.1.13/src/testkit/schema.py +140 -0
- fyre_toolkit-0.1.13/src/testkit/utils.py +328 -0
- fyre_toolkit-0.1.13/src/testkit/validator.py +401 -0
- fyre_toolkit-0.1.13/tests/__init__.py +0 -0
- fyre_toolkit-0.1.13/tests/conftest.py +26 -0
- fyre_toolkit-0.1.13/tests/resources/invalid_case.yaml +4 -0
- fyre_toolkit-0.1.13/tests/resources/multiple_valid_cases.yaml +37 -0
- fyre_toolkit-0.1.13/tests/resources/valid_one_case.yaml +16 -0
- fyre_toolkit-0.1.13/tests/test_suite_from_yaml.py +121 -0
- fyre_toolkit-0.1.13/tests/test_testkit_aggregator.py +96 -0
- fyre_toolkit-0.1.13/tests/test_testkit_genereator.py +1069 -0
- fyre_toolkit-0.1.13/tests/test_testkit_module.py +145 -0
- fyre_toolkit-0.1.13/tests/test_testkit_parser.py +79 -0
- fyre_toolkit-0.1.13/tests/test_testkit_schema.py +177 -0
- fyre_toolkit-0.1.13/tests/test_testkit_utils.py +1124 -0
- fyre_toolkit-0.1.13/tests/test_testkit_validator.py +900 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
end_of_line = lf
|
|
5
|
+
insert_final_newline = true
|
|
6
|
+
|
|
7
|
+
[*.py]
|
|
8
|
+
charset = utf-8
|
|
9
|
+
indent_style = space
|
|
10
|
+
indent_size = 4
|
|
11
|
+
continuation_indent_size = 4
|
|
12
|
+
spaces_around_operators = 1
|
|
13
|
+
max_line_length = 80
|
|
14
|
+
|
|
15
|
+
[Makefile]
|
|
16
|
+
indent_style = tab
|
|
17
|
+
tab_width = 2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: 功能建议
|
|
2
|
+
description: 对本项目提出一个功能建议
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
labels: ["feature"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
感谢提出功能建议,我们将仔细考虑!
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: related-problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: 你的功能建议是否和某个问题相关?
|
|
14
|
+
description: 清晰并简洁地描述问题是什么,例如,当我...时,我总是感到困扰。
|
|
15
|
+
validations:
|
|
16
|
+
required: false
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: desired-solution
|
|
19
|
+
attributes:
|
|
20
|
+
label: 你希望看到什么解决方案?
|
|
21
|
+
description: 清晰并简洁地描述你希望发生的事情。
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: alternatives
|
|
26
|
+
attributes:
|
|
27
|
+
label: 你考虑过哪些替代方案?
|
|
28
|
+
description: 清晰并简洁地描述你考虑过的任何替代解决方案或功能。
|
|
29
|
+
validations:
|
|
30
|
+
required: false
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: additional-context
|
|
33
|
+
attributes:
|
|
34
|
+
label: 你有其他上下文或截图吗?
|
|
35
|
+
description: 在此处添加有关功能请求的任何其他上下文或截图。
|
|
36
|
+
validations:
|
|
37
|
+
required: false
|
|
38
|
+
- type: checkboxes
|
|
39
|
+
attributes:
|
|
40
|
+
label: 意向参与贡献
|
|
41
|
+
options:
|
|
42
|
+
- label: 我有意向参与具体功能的开发实现并将代码贡献回到本项目
|
|
43
|
+
required: false
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: 问题反馈
|
|
2
|
+
description: 当你在代码中发现了一个问题, 导致应用崩溃或抛出异常, 或者有一个组件存在问题, 或者某些地方看起来不对劲.
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关开发或使用文档:
|
|
10
|
+
- https://...
|
|
11
|
+
- type: checkboxes
|
|
12
|
+
attributes:
|
|
13
|
+
label: 这个问题是否已经存在?
|
|
14
|
+
options:
|
|
15
|
+
- label: 我已经搜索过现有的问题
|
|
16
|
+
required: false
|
|
17
|
+
- type: textarea
|
|
18
|
+
attributes:
|
|
19
|
+
label: 如何复现
|
|
20
|
+
description: 请详细告诉我们如何复现你遇到的问题,如涉及代码,可提供一个最小代码示例,并使用反引号```附上它
|
|
21
|
+
placeholder: |
|
|
22
|
+
1. ...
|
|
23
|
+
2. ...
|
|
24
|
+
3. ...
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: textarea
|
|
28
|
+
attributes:
|
|
29
|
+
label: 预期结果
|
|
30
|
+
description: 请告诉我们你预期会发生什么。
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
- type: textarea
|
|
34
|
+
attributes:
|
|
35
|
+
label: 实际结果
|
|
36
|
+
description: 请告诉我们实际发生了什么。
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: textarea
|
|
40
|
+
attributes:
|
|
41
|
+
label: 截图或视频
|
|
42
|
+
description: 如果可以的话,上传任何关于 bug 的截图。
|
|
43
|
+
value: |
|
|
44
|
+
[在这里上传图片]
|
|
45
|
+
- type: dropdown
|
|
46
|
+
id: version
|
|
47
|
+
attributes:
|
|
48
|
+
label: 版本
|
|
49
|
+
description: 你当前正在使用我们软件的哪个版本/分支?
|
|
50
|
+
options:
|
|
51
|
+
- 0.1 (默认)
|
|
52
|
+
- 0.2
|
|
53
|
+
validations:
|
|
54
|
+
required: true
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# This workflow will install Python dependencies, run tests, lint and build with a variety of Python versions
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
|
3
|
+
|
|
4
|
+
name: pytest
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: ["main"]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: ["feature-**"]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-artifacts:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
uses: actions/setup-python@v6
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install --upgrade pip
|
|
31
|
+
python -m pip install uv flake8 pytest ruff
|
|
32
|
+
if [ -f pyproject.toml ]; then uv sync; fi
|
|
33
|
+
env:
|
|
34
|
+
CI: true
|
|
35
|
+
- name: Install pypa/build
|
|
36
|
+
run: |
|
|
37
|
+
python -m pip install build --user
|
|
38
|
+
- name: Lint with ruff
|
|
39
|
+
run: |
|
|
40
|
+
# stop the build if there are Python syntax errors or undefined names
|
|
41
|
+
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
|
42
|
+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
|
43
|
+
# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
|
44
|
+
uv run ruff check
|
|
45
|
+
- name: Test with pytest
|
|
46
|
+
run: |
|
|
47
|
+
uv run pytest --disable-warnings --tb=short
|
|
48
|
+
- name: Build a binary wheel and a source tarball
|
|
49
|
+
run: python3 -m build
|
|
50
|
+
- name: Store the distribution packages
|
|
51
|
+
if: matrix.python-version == '3.12'
|
|
52
|
+
uses: actions/upload-artifact@v5
|
|
53
|
+
with:
|
|
54
|
+
name: python-package-distributions
|
|
55
|
+
path: dist/
|
|
56
|
+
|
|
57
|
+
bump-version:
|
|
58
|
+
# Use a condition to prevent infinite loops from the bot's own commits
|
|
59
|
+
if: "! contains(github.event.head_commit.message, 'Bump version')"
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
needs: build-artifacts
|
|
62
|
+
permissions:
|
|
63
|
+
contents: write
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout code
|
|
67
|
+
uses: actions/checkout@v5
|
|
68
|
+
with:
|
|
69
|
+
fetch-depth: 0
|
|
70
|
+
token: ${{ secrets.BOT_TOKEN }}
|
|
71
|
+
|
|
72
|
+
- name: Set up Python
|
|
73
|
+
uses: actions/setup-python@v6
|
|
74
|
+
with:
|
|
75
|
+
python-version: "3.12"
|
|
76
|
+
|
|
77
|
+
- name: Install and link bump2version
|
|
78
|
+
run: |
|
|
79
|
+
# Install to the specific local directory the action expects
|
|
80
|
+
python -m pip install --user bump2version
|
|
81
|
+
|
|
82
|
+
# Ensure the directory exists and add to PATH
|
|
83
|
+
mkdir -p /home/runner/.local/bin
|
|
84
|
+
echo "/home/runner/.local/bin" >> $GITHUB_PATH
|
|
85
|
+
|
|
86
|
+
# Verify installation path
|
|
87
|
+
which bumpversion || echo "Warning: bumpversion not found in PATH"
|
|
88
|
+
which bump2version || echo "Warning: bump2version not found in PATH"
|
|
89
|
+
|
|
90
|
+
- name: Bump Version and Push
|
|
91
|
+
run: |
|
|
92
|
+
# 1. Configure Git identity
|
|
93
|
+
git config --global user.name "Automated Version Bump Bot"
|
|
94
|
+
git config --global user.email "actions@github.com"
|
|
95
|
+
|
|
96
|
+
# 2. Extract current version from file to avoid the "parse" error
|
|
97
|
+
# This finds the first x.y.z string in your file
|
|
98
|
+
CURRENT_VERSION=$(grep -oE "[0-9]+\.[0-9]+\.[0-9]+" src/testkit/__init__.py | head -1)
|
|
99
|
+
|
|
100
|
+
# 3. Execute bump2version directly
|
|
101
|
+
# This updates [src/testkit/__init__.py]
|
|
102
|
+
# and creates a git commit automatically
|
|
103
|
+
bump2version patch \
|
|
104
|
+
--current-version "$CURRENT_VERSION" \
|
|
105
|
+
--commit \
|
|
106
|
+
--message "Bump version: {current_version} -> {new_version} [skip ci]" \
|
|
107
|
+
src/testkit/__init__.py
|
|
108
|
+
|
|
109
|
+
# 4. Push the changes
|
|
110
|
+
git push origin main
|
|
111
|
+
|
|
112
|
+
publish-to-pypi:
|
|
113
|
+
name: >-
|
|
114
|
+
Publish Python 🐍 distribution 📦 to PyPI
|
|
115
|
+
if: startsWith(github.ref, 'refs/heads/main') && !contains(github.event.head_commit.message, 'Bump version')
|
|
116
|
+
needs: bump-version
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
environment:
|
|
119
|
+
name: pypi
|
|
120
|
+
url: https://pypi.org/p/fyre-toolkit/
|
|
121
|
+
permissions:
|
|
122
|
+
id-token: write
|
|
123
|
+
|
|
124
|
+
steps:
|
|
125
|
+
- name: Download all the dists
|
|
126
|
+
uses: actions/download-artifact@v6
|
|
127
|
+
with:
|
|
128
|
+
name: python-package-distributions
|
|
129
|
+
path: dist/
|
|
130
|
+
- name: Publish distribution 📦 to PyPI
|
|
131
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
pkg_deps/
|
|
29
|
+
requirements.txt
|
|
30
|
+
|
|
31
|
+
# PyInstaller
|
|
32
|
+
# Usually these files are written by a python script from a template
|
|
33
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
34
|
+
*.manifest
|
|
35
|
+
*.spec
|
|
36
|
+
|
|
37
|
+
# Installer logs
|
|
38
|
+
pip-log.txt
|
|
39
|
+
pip-delete-this-directory.txt
|
|
40
|
+
|
|
41
|
+
# Unit test / coverage reports
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.nox/
|
|
45
|
+
.coverage
|
|
46
|
+
.coverage.*
|
|
47
|
+
.cache
|
|
48
|
+
nosetests.xml
|
|
49
|
+
coverage.xml
|
|
50
|
+
*-results.xml
|
|
51
|
+
pytest_result.xml
|
|
52
|
+
*_report.html
|
|
53
|
+
*.cover
|
|
54
|
+
*.py,cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
db.sqlite3-journal
|
|
68
|
+
|
|
69
|
+
# Flask stuff:
|
|
70
|
+
instance/
|
|
71
|
+
.webassets-cache
|
|
72
|
+
|
|
73
|
+
# Scrapy stuff:
|
|
74
|
+
.scrapy
|
|
75
|
+
|
|
76
|
+
# Sphinx documentation
|
|
77
|
+
docs/_build/
|
|
78
|
+
|
|
79
|
+
# PyBuilder
|
|
80
|
+
.pybuilder/
|
|
81
|
+
target/
|
|
82
|
+
|
|
83
|
+
# Jupyter Notebook
|
|
84
|
+
.ipynb_checkpoints
|
|
85
|
+
|
|
86
|
+
# IPython
|
|
87
|
+
profile_default/
|
|
88
|
+
ipython_config.py
|
|
89
|
+
|
|
90
|
+
# pyenv
|
|
91
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
92
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
93
|
+
# .python-version
|
|
94
|
+
|
|
95
|
+
# pipenv
|
|
96
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
97
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
98
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
99
|
+
# install all needed dependencies.
|
|
100
|
+
#Pipfile.lock
|
|
101
|
+
|
|
102
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
103
|
+
__pypackages__/
|
|
104
|
+
|
|
105
|
+
# Celery stuff
|
|
106
|
+
celerybeat-schedule
|
|
107
|
+
celerybeat.pid
|
|
108
|
+
|
|
109
|
+
# SageMath parsed files
|
|
110
|
+
*.sage.py
|
|
111
|
+
|
|
112
|
+
# Environments
|
|
113
|
+
.env
|
|
114
|
+
.venv
|
|
115
|
+
env/
|
|
116
|
+
venv/
|
|
117
|
+
ENV/
|
|
118
|
+
env.bak/
|
|
119
|
+
venv.bak/
|
|
120
|
+
|
|
121
|
+
# Spyder project settings
|
|
122
|
+
.spyderproject
|
|
123
|
+
.spyproject
|
|
124
|
+
|
|
125
|
+
# Rope project settings
|
|
126
|
+
.ropeproject
|
|
127
|
+
|
|
128
|
+
# mkdocs documentation
|
|
129
|
+
/site
|
|
130
|
+
|
|
131
|
+
# mypy
|
|
132
|
+
.mypy_cache/
|
|
133
|
+
.dmypy.json
|
|
134
|
+
dmypy.json
|
|
135
|
+
|
|
136
|
+
# Pyre type checker
|
|
137
|
+
.pyre/
|
|
138
|
+
|
|
139
|
+
# pytype static type analyzer
|
|
140
|
+
.pytype/
|
|
141
|
+
|
|
142
|
+
# Cython debug symbols
|
|
143
|
+
cython_debug/
|
|
144
|
+
|
|
145
|
+
# UV
|
|
146
|
+
uv.lock
|
|
147
|
+
.ruff_cache/
|
|
148
|
+
|
|
149
|
+
# PyCharm
|
|
150
|
+
.idea/
|
|
151
|
+
|
|
152
|
+
# SonarQube
|
|
153
|
+
.scannerwork/
|
|
154
|
+
|
|
155
|
+
# Others
|
|
156
|
+
workspace-*/
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# AGENTS.md — Fyre Toolkit
|
|
2
|
+
|
|
3
|
+
> Guidelines for agentic coding agents operating in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Python 3.12+ package (`fyre-toolkit`) that generates pytest test cases from YAML definitions using Pydantic schema validation. Built with `uv` + `hatchling`.
|
|
8
|
+
|
|
9
|
+
## Build / Lint / Test Commands
|
|
10
|
+
|
|
11
|
+
### Dependency Management
|
|
12
|
+
```bash
|
|
13
|
+
uv sync # Install all deps (including dev)
|
|
14
|
+
uv lock --no-cache # Re-lock dependencies
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Linting
|
|
18
|
+
```bash
|
|
19
|
+
uv run ruff check # Lint src/ (excludes tests/)
|
|
20
|
+
uv run ruff check --fix # Auto-fix linting issues
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Type Checking
|
|
24
|
+
```bash
|
|
25
|
+
uv run mypy src/ # Strict type checking
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Testing
|
|
29
|
+
```bash
|
|
30
|
+
uv run pytest # Run all tests (with coverage)
|
|
31
|
+
uv run pytest -k "keyword" # Run tests matching keyword
|
|
32
|
+
uv run pytest tests/test_testkit_parser.py # Single file
|
|
33
|
+
uv run pytest tests/test_testkit_parser.py::TestLoadYamlFile # Single class
|
|
34
|
+
uv run pytest tests/test_testkit_parser.py::TestLoadYamlFile::test_load_valid_file # Single test
|
|
35
|
+
uv run pytest -v # Verbose output
|
|
36
|
+
uv run pytest --no-cov # Run without coverage (faster)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Coverage
|
|
40
|
+
```bash
|
|
41
|
+
uv run pytest --cov=src --cov-report=term # Terminal report
|
|
42
|
+
uv run pytest --cov=src --cov-report=html # HTML report in htmlcov/
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Building
|
|
46
|
+
```bash
|
|
47
|
+
uv build --wheel # Build wheel distribution
|
|
48
|
+
uv run twine upload ... # Publish to PyPI
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### CI Pipeline (Jenkinsfile)
|
|
52
|
+
- **PR branches**: `pytest --cov=src` + `diff-cover --fail-under=80`
|
|
53
|
+
- **Main branch**: `pytest --cov=src --cov-fail-under=80` + SonarQube scan
|
|
54
|
+
|
|
55
|
+
## Code Style
|
|
56
|
+
|
|
57
|
+
### Imports
|
|
58
|
+
- Standard library → third-party → local, separated by blank lines (isort ordering via ruff `I`)
|
|
59
|
+
- Use `from pathlib import Path` instead of `os.path`
|
|
60
|
+
- Use `collections.abc` for type hints (`Callable`, `Iterator`)
|
|
61
|
+
|
|
62
|
+
### Formatting
|
|
63
|
+
- 4-space indentation, UTF-8 encoding
|
|
64
|
+
- Max line length: 80 characters (ruff ignores E501 but .editorconfig enforces 80)
|
|
65
|
+
- LF line endings, trailing newline required
|
|
66
|
+
- Use `uv run ruff check --fix` before committing
|
|
67
|
+
|
|
68
|
+
### Type Hints
|
|
69
|
+
- **mypy strict mode** is enforced — no `Any`, no suppressed errors
|
|
70
|
+
- All function parameters and return types must be annotated
|
|
71
|
+
- Use `collections.abc` types: `Callable[[str, str], str]`, `Iterator[str]`
|
|
72
|
+
- Pydantic v2 models for data structures (`model_dump()`, not `.dict()`)
|
|
73
|
+
|
|
74
|
+
### Naming Conventions
|
|
75
|
+
- Modules: `snake_case` (e.g., `generator.py`, `testkit_utils.py`)
|
|
76
|
+
- Classes: `PascalCase` (e.g., `TestCase`, `TestSuite`, `TestLoadYamlFile`)
|
|
77
|
+
- Functions/variables: `snake_case` (e.g., `sanitize_identifier`, `test_suite`)
|
|
78
|
+
- Constants: `UPPER_SNAKE_CASE` (e.g., `PYTEST_MODULE_HEADER`)
|
|
79
|
+
- Private helpers: leading underscore (e.g., `_load_yaml_file`, `_check_package`)
|
|
80
|
+
- Test classes: `Test` + CamelCase (e.g., `TestLoadYamlFile`)
|
|
81
|
+
- Test methods: `test_` + snake_case (e.g., `test_load_valid_file`)
|
|
82
|
+
|
|
83
|
+
### Docstrings
|
|
84
|
+
- Google-style with triple-quoted strings
|
|
85
|
+
- Include: brief description, Args, Returns, Raises, Example sections
|
|
86
|
+
- Doctest examples encouraged for pure functions
|
|
87
|
+
|
|
88
|
+
### Error Handling
|
|
89
|
+
- Raise specific exceptions: `TypeError`, `ValueError`, `FileNotFoundError`, `RuntimeError`
|
|
90
|
+
- Use descriptive error messages with context (e.g., f-strings with file paths)
|
|
91
|
+
- Chain exceptions with `from e` when re-raising (except where ruff allows `B904`)
|
|
92
|
+
- Use `pytest.raises` for testing expected exceptions
|
|
93
|
+
- Log exceptions with `logging.exception()` before re-raising in library code
|
|
94
|
+
|
|
95
|
+
### Testing Patterns
|
|
96
|
+
- Use pytest fixtures in `conftest.py` for shared test data
|
|
97
|
+
- Class-based tests for grouping related test methods
|
|
98
|
+
- Use `unittest.mock.patch` for mocking external dependencies
|
|
99
|
+
- Use `tmp_path` fixture for temporary file testing
|
|
100
|
+
- Integration tests alongside unit tests (see `test_integration_*`)
|
|
101
|
+
- Test resources (YAML files) go in `tests/resources/`
|
|
102
|
+
|
|
103
|
+
### Pydantic Models
|
|
104
|
+
- Use Pydantic v2 (`model_dump()`, not `.dict()`)
|
|
105
|
+
- Models defined in `testkit/schema.py` — do not duplicate
|
|
106
|
+
- Validation errors surface as `pydantic.ValidationError`
|
|
107
|
+
|
|
108
|
+
## Project Structure
|
|
109
|
+
```
|
|
110
|
+
src/testkit/ # Main package
|
|
111
|
+
__init__.py # Public API exports, __version__
|
|
112
|
+
schema.py # Pydantic models (TestCase, TestSuite, etc.)
|
|
113
|
+
parser.py # YAML loading and validation
|
|
114
|
+
generator.py # Pytest code generation
|
|
115
|
+
aggregator.py # Component aggregation
|
|
116
|
+
utils.py # Utility functions
|
|
117
|
+
tests/ # Test suite
|
|
118
|
+
conftest.py # Shared pytest fixtures
|
|
119
|
+
resources/ # Test data (YAML files)
|
|
120
|
+
test_testkit_*.py # Test modules (one per source module)
|
|
121
|
+
examples/ # Usage examples
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Key Constraints
|
|
125
|
+
- **Never suppress type errors** (`as any`, `# type: ignore`, `@ts-ignore`)
|
|
126
|
+
- **Never commit** unless explicitly requested
|
|
127
|
+
- **Match existing patterns** — this codebase is disciplined; follow its style
|
|
128
|
+
- **Fix minimally** — do not refactor while fixing bugs
|
|
129
|
+
- **Run `ruff check`** on changed files before declaring work complete
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
pipeline {
|
|
2
|
+
agent { label 'python' }
|
|
3
|
+
environment {
|
|
4
|
+
PATH="${env.HOME}/.local/bin:${env.PATH}"
|
|
5
|
+
SONAR_HOST_URL="http://192.168.119.2:9000"
|
|
6
|
+
SONAR_PROJECT_KEY="fyre_toolkit"
|
|
7
|
+
SONAR_TOKEN=credentials('sonar')
|
|
8
|
+
UV_PUBLISH_URL="http://192.168.119.2:8082/repository/pypi-internal/"
|
|
9
|
+
UV_PUBLISH_USERNAME="devs"
|
|
10
|
+
UV_PUBLISH_PASSWORD=credentials("uv")
|
|
11
|
+
}
|
|
12
|
+
options {
|
|
13
|
+
skipStagesAfterUnstable()
|
|
14
|
+
}
|
|
15
|
+
stages {
|
|
16
|
+
stage ('Setup') {
|
|
17
|
+
steps {
|
|
18
|
+
script {
|
|
19
|
+
sh '''
|
|
20
|
+
printenv
|
|
21
|
+
uv lock --no-cache
|
|
22
|
+
uv sync --no-cache --no-editable
|
|
23
|
+
'''
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
stage ('Lint') {
|
|
28
|
+
steps {
|
|
29
|
+
sh 'uv run ruff check'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
stage ('Build') {
|
|
33
|
+
steps {
|
|
34
|
+
sh 'uv build --wheel'
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
stage ('Feature Branch Test') {
|
|
39
|
+
when { branch 'PR-*' }
|
|
40
|
+
steps {
|
|
41
|
+
sh '''
|
|
42
|
+
uv run pytest \
|
|
43
|
+
--cov=src \
|
|
44
|
+
--junitxml=pytest_result.xml
|
|
45
|
+
'''
|
|
46
|
+
sh '''
|
|
47
|
+
uv run diff-cover \
|
|
48
|
+
--format html:diff_report.html ./coverage.xml \
|
|
49
|
+
--compare-branch origin/main \
|
|
50
|
+
--ignore-unstaged \
|
|
51
|
+
--ignore-staged \
|
|
52
|
+
--fail-under=80
|
|
53
|
+
'''
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
stage ('Main Branch Test') {
|
|
57
|
+
when { branch 'main' }
|
|
58
|
+
steps {
|
|
59
|
+
sh '''
|
|
60
|
+
uv run pytest \
|
|
61
|
+
--cov=src \
|
|
62
|
+
--cov-fail-under=80 \
|
|
63
|
+
--junitxml=pytest_result.xml
|
|
64
|
+
'''
|
|
65
|
+
sh '''
|
|
66
|
+
uv run diff-cover \
|
|
67
|
+
--format html:diff_report.html ./coverage.xml \
|
|
68
|
+
--compare-branch HEAD^ \
|
|
69
|
+
--ignore-unstaged \
|
|
70
|
+
--ignore-staged \
|
|
71
|
+
--fail-under=50
|
|
72
|
+
'''
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
stage ('Quality Gate') {
|
|
76
|
+
when { anyOf { branch 'main'; branch 'release-*' } }
|
|
77
|
+
steps {
|
|
78
|
+
withEnv(["SONAR_TOKEN=${SONAR_TOKEN}"]) {
|
|
79
|
+
sh '''
|
|
80
|
+
$SONAR_SCANNER_HOME/bin/sonar-scanner \
|
|
81
|
+
-Dsonar.projectKey=${SONAR_PROJECT_KEY} \
|
|
82
|
+
-Dsonar.sources=src \
|
|
83
|
+
-Dsonar.exclusions=tests/** \
|
|
84
|
+
-Dsonar.python.coverage.reportPaths=./coverage.xml \
|
|
85
|
+
-Dsonar.host.url=${SONAR_HOST_URL} \
|
|
86
|
+
-Dsonar.login=${SONAR_TOKEN}
|
|
87
|
+
'''
|
|
88
|
+
|
|
89
|
+
// timeout(time: 1, unit: 'HOURS') {
|
|
90
|
+
// waitForQualityGate abortPipeline: true
|
|
91
|
+
// }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
stage ('Install') {
|
|
96
|
+
when { anyOf { branch 'main'; branch 'release-*' } }
|
|
97
|
+
steps {
|
|
98
|
+
sh 'uv pip install --upgrade dist/fyre_toolkit-0.1.0-py3-none-any.whl'
|
|
99
|
+
sh 'uv run python -c "from testkit import __version__; print(__version__)"'
|
|
100
|
+
sh 'uv pip uninstall fyre-toolkit'
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
stage ('Publish') {
|
|
104
|
+
when { anyOf { branch 'main'; branch 'release-*' } }
|
|
105
|
+
steps {
|
|
106
|
+
echo 'Start Publish...'
|
|
107
|
+
// sh 'uv publish --username ${UV_PUBLISH_USERNAME} --password ${UV_PUBLISH_PASSWORD} --publish-url ${UV_PUBLISH_URL}'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
post {
|
|
112
|
+
always {
|
|
113
|
+
archiveArtifacts artifacts: '**/coverage.xml, **/diff_report.html, dist/fyre_toolkit-0.1.0-py3-none-any.whl', allowEmptyArchive: true
|
|
114
|
+
echo "Pipeline completed."
|
|
115
|
+
}
|
|
116
|
+
success {
|
|
117
|
+
echo "Pipeline succeeded."
|
|
118
|
+
}
|
|
119
|
+
failure {
|
|
120
|
+
echo "Pipeline failed. Check logs or SonarQube for details."
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|