Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ba13401
docs: point progress.md at the workspace items still open
JE-Chen Sep 25, 2026
08ad366
Wait 7 days before Dependabot proposes a new release
JE-Chen Sep 25, 2026
28ede73
docs: CLAUDE.md: look up SonarCloud/Codacy findings through their API…
JE-Chen Sep 25, 2026
b6bd677
docs: CLAUDE.md: the Codacy project token only works for its own proj…
JE-Chen Sep 25, 2026
ad80940
Pin the dev environment to the package's PySide6 6.11.2
JE-Chen Sep 25, 2026
e7fbbf1
List Python 3.11 to 3.14 in the classifiers, as CI tests them
JE-Chen Sep 25, 2026
10dd122
docs: progress.md: record the eight planned features (#6-#13)
JE-Chen Sep 30, 2026
4810743
feat: infer OpenAPI from saved reports via CLI, MCP and executor
JE-Chen Sep 30, 2026
2771aba
fix: make imported, scaffolded and AI-generated actions runnable
JE-Chen Sep 30, 2026
39557ec
feat: serve WebSocket and gRPC endpoints from the mock server
JE-Chen Sep 30, 2026
cac9ee4
feat: add Pact-style bidirectional contract testing
JE-Chen Sep 30, 2026
b2a3c7a
feat: add an Anthropic reference AI backend and backend selection
JE-Chen Sep 30, 2026
2884830
feat: run APITestka requests as a LoadDensity load test
JE-Chen Sep 30, 2026
e6965a6
feat: track per-endpoint latency trends and flag anomalies
JE-Chen Sep 30, 2026
c8d774e
feat: add the test-as-spec loop (drift, coverage, generated tests)
JE-Chen Sep 30, 2026
3f50a17
feat: redesign the GUI with sidebar pages, a request workspace and th…
JE-Chen Sep 30, 2026
6a11111
chore: mark the package as Beta instead of Pre-Alpha
JE-Chen Sep 30, 2026
7b9d0dc
test: skip the Qt widget tests where PySide6 cannot load (no libEGL o…
JE-Chen Sep 30, 2026
2509703
docs: progress.md: run the Qt widget tests on Linux CI (#14)
JE-Chen Sep 30, 2026
0b63b2e
ci: install Qt's system libraries on Linux and require the GUI tests
JE-Chen Oct 1, 2026
68d259a
docs: record that the GUI widget tests run on Linux CI (#14)
JE-Chen Oct 1, 2026
34d1cb7
ci: give every workflow job a timeout
JE-Chen Oct 1, 2026
54f5904
fix: reformat_xml_file raises APITesterXMLException for bad or refuse…
JE-Chen Oct 1, 2026
ae63806
refactor: clear the package's lint findings without changing behaviour
JE-Chen Oct 1, 2026
0bbff4d
security: gate AT_add_package_to_executor behind a package allowlist
JE-Chen Oct 1, 2026
ef8a8d4
fix: record the httpx request_url as text so OpenAPI export can parse it
JE-Chen Oct 1, 2026
8f3e7f0
fix: keep GUI tasks and state alive across language switches and wind…
JE-Chen Oct 1, 2026
8a32ded
fix: report an unknown executor command by name instead of a NoneType…
JE-Chen Oct 1, 2026
1f28c26
refactor: build the executor and its helpers on je_action_core
JE-Chen Oct 1, 2026
50af6d1
build: pin je_action_core to 19bfe0a, where add_package_to_executor r…
JE-Chen Oct 1, 2026
0356b27
docs: point progress #15 at the package gate's new home in je_action_…
JE-Chen Oct 1, 2026
36195c7
build: install je_action_core from PyPI instead of the GitHub pin
JE-Chen Oct 1, 2026
4a741fc
ci: publish je_api_testka_dev from CI on a tested push to dev that ch…
JE-Chen Oct 1, 2026
06a295d
build: keep the test suite out of the sdist
JE-Chen Oct 1, 2026
9512155
refactor: read Dependabot's update blocks through one helper in the w…
JE-Chen Oct 1, 2026
e9e092f
ci: install hash-locked build tooling in the stable publish job
JE-Chen Oct 1, 2026
a3ccb25
ci: build with the locked setuptools in both publish jobs
JE-Chen Oct 1, 2026
468a4b1
ci: resolve the publish lock with the 7-day cut-off the other locks use
JE-Chen Oct 1, 2026
b0e5c01
feat: capture shared request outcomes in HTTP wrappers
JE-Chen Oct 2, 2026
d64e06c
fix: preserve monotonic timing and failure kinds
JE-Chen Oct 2, 2026
7aba6ff
fix: exclude configuration failures from request measurements
JE-Chen Oct 2, 2026
a78a1f8
feat: exit 1 when a run failed and write reports below the artifact dir
JE-Chen Oct 8, 2026
a5c0bfe
Merge pull request #146 from Integration-Automation/feat/shared-record
JE-Chen Oct 11, 2026
ce7ac3e
Merge dev and preserve both request-record and runner-support update …
JE-Chen Oct 11, 2026
2bd7786
Merge pull request #149 from Integration-Automation/feat/testpioneer-…
JE-Chen Oct 11, 2026
5d4d6c8
chore: merge current main release metadata into dev
JE-Chen Oct 11, 2026
980c03a
fix: constrain contract paths and bound reply fence parsing
JE-Chen Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,27 @@
version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
# Location of package manifests. "/" does not reach .github/requirements, which holds the
# hash-locked files the CI test job and the two publish jobs install (ci.txt, publish.txt).
directories:
- "/"
- "/.github/requirements"
# Updates belong on dev: main is the released branch and merging into it
# publishes, so a PR opened against main just sits there.
target-branch: "dev"
schedule:
interval: "daily"
# A new release waits 7 days before Dependabot proposes it, so a
# compromised version is more likely to be found and yanked first.
# Dependabot's own default is 3 days. Security updates are not delayed.
cooldown:
default-days: 7
# Workflow actions are pinned to commit SHAs with the version as a comment
# (test_workflow_actions.py); Dependabot moves both together.
- package-ecosystem: "github-actions"
directory: "/"
target-branch: "dev"
schedule:
interval: "weekly"
cooldown:
default-days: 7
7 changes: 5 additions & 2 deletions .github/requirements/ci.in
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# What the CI test job installs; ci.txt is generated from this file (the command is in ci.yml).
# Runtime dependencies (pyproject.toml), the gui and mcp extras, and the test tools.
# Runtime dependencies (pyproject.toml), the gui, mcp, websocket, grpc and ai extras, and the test tools.
requests
Flask
httpx
defusedxml
je_action_core>=0.0.1
PySide6==6.11.2
qt-material
mcp>=1.28.1,<3
websockets>=12.0
grpcio>=1.60
anthropic>=1.0,<2
pytest
pytest-asyncio
pytest-timeout
477 changes: 469 additions & 8 deletions .github/requirements/ci.txt

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions .github/requirements/publish.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# What the two jobs that upload to PyPI install: publish-dev in ci.yml and publish in publish.yml.
# publish.txt is generated from this file; the command is in both workflows, above the install step.
build
twine
# The build backend. Both jobs run `python -m build --no-isolation`, so the backend is this locked one
# and not whatever is newest on PyPI when the job runs. It must satisfy `build-system.requires` in
# pyproject.toml and dev.toml; test/test_workflow_actions.py fails when it does not.
setuptools
472 changes: 472 additions & 0 deletions .github/requirements/publish.txt

Large diffs are not rendered by default.

78 changes: 76 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ permissions:
jobs:
test:
runs-on: ${{ matrix.os }}
timeout-minutes: 15 # about 3x the slowest recent run, at least 15
strategy:
fail-fast: false
matrix:
Expand All @@ -31,13 +32,86 @@ jobs:
python-version: ${{ matrix.python-version }}

# Hash-locked, wheels-only, one file for every OS and Python in the matrix. Regenerate with
# uv pip compile .github/requirements/ci.in --universal --python-version 3.10 # --generate-hashes --only-binary :all: -o .github/requirements/ci.txt
# uv pip compile .github/requirements/ci.in --universal --python-version 3.10 \
# --generate-hashes --only-binary :all: -o .github/requirements/ci.txt
- name: Install dependencies
run: |
pip install --require-hashes --only-binary :all: -r .github/requirements/ci.txt

# The tests import the checked-out source, not a published package.
# PySide6's Qt libraries load these at import; the Ubuntu runner image lacks libEGL.so.1 at least.
# The list is the ELF NEEDED entries of QtGui, QtWidgets and the offscreen plugin outside the base system.
- name: Install Qt runtime libraries (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libegl1 libgl1 libx11-6 libxkbcommon0 libfontconfig1 libfreetype6

# The tests import the checked-out source, not a published package. APITESTKA_REQUIRE_QT turns a
# failed PySide6 import into an error, so the GUI widget tests cannot silently skip in CI.
- name: Run tests
env:
PYTHONPATH: ${{ github.workspace }}
APITESTKA_REQUIRE_QT: "1"
run: python -m pytest test/ -v

publish-dev:
# The dev channel. A push to dev that passes the tests is built from dev.toml and uploaded when
# it is still the tip of dev and ships something the newest je_api_testka_dev does not.
# scripts/dev_release.py picks the version from PyPI, so nothing is committed back.
# This workflow also runs for main, pull requests and the schedule: the condition keeps those out.
name: Publish je_api_testka_dev to PyPI
needs: [test]
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
runs-on: ubuntu-latest
timeout-minutes: 15 # about 3x the slowest recent run, at least 15
concurrency:
group: publish-dev
cancel-in-progress: false

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"

# Hash-locked and wheels-only, like the test job: this job holds the PyPI token. Regenerate with
# uv pip compile .github/requirements/publish.in --generate-hashes --python-version 3.12 \
# --python-platform x86_64-manylinux_2_28 --only-binary :all: --exclude-newer 2026-09-24 \
# -o .github/requirements/publish.txt
# (--exclude-newer keeps the 7-day wait Dependabot applies; move the date when regenerating)
- name: Install build tooling
run: |
python -m pip install --require-hashes --only-binary :all: -r .github/requirements/publish.txt

- name: Write pyproject.toml from dev.toml with the next version
run: python scripts/dev_release.py prepare

# --no-isolation: the backend is the setuptools locked in publish.txt, not a fresh download.
- name: Build distribution
run: python -m build --no-isolation

- name: Verify distribution metadata
run: python -m twine check dist/*

- name: Compare with the newest published wheel
id: compare
run: python scripts/dev_release.py changed dist

# A run that finishes after a newer push would otherwise publish older code as the newest release.
- name: Check that this commit is still the tip of dev
id: tip
run: |
tip="$(git ls-remote origin refs/heads/dev | cut -f1)"
if [ "$tip" = "$GITHUB_SHA" ]; then current=true; else current=false; fi
echo "current=$current" >> "$GITHUB_OUTPUT"

- name: Publish to PyPI
if: steps.compare.outputs.changed == 'true' && steps.tip.outputs.current == 'true'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: python -m twine upload --non-interactive dist/*
15 changes: 11 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ concurrency:
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 15 # about 3x the slowest recent run, at least 15
if: "!contains(github.event.head_commit.message, 'chore: bump version')"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -26,10 +27,15 @@ jobs:
with:
python-version: "3.12"

- name: Install build tools
# Hash-locked and wheels-only, the same file as the publish-dev job of ci.yml: this job holds the
# PyPI token. Regenerate with
# uv pip compile .github/requirements/publish.in --generate-hashes --python-version 3.12 \
# --python-platform x86_64-manylinux_2_28 --only-binary :all: --exclude-newer 2026-09-24 \
# -o .github/requirements/publish.txt
# (--exclude-newer keeps the 7-day wait Dependabot applies; move the date when regenerating)
- name: Install build tooling
run: |
python -m pip install --upgrade pip
pip install build twine
python -m pip install --require-hashes --only-binary :all: -r .github/requirements/publish.txt

- name: Bump patch version in pyproject.toml
id: bump
Expand Down Expand Up @@ -59,8 +65,9 @@ jobs:
print(f"Bumped version -> {new_version}")
EOF

# --no-isolation: the backend is the setuptools locked in publish.txt, not a fresh download.
- name: Build distribution
run: python -m build
run: python -m build --no-isolation

- name: Publish to PyPI
env:
Expand Down
17 changes: 10 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
APITestka (`je_api_testka`) is a lightweight, cross-platform Python framework for automated API testing. Supports HTTP/HTTPS, SOAP/XML, JSON with `requests` and `httpx` backends.

- **Python**: 3.10+
- **Dependencies**: `requests`, `Flask`, `httpx`
- **Optional GUI**: `PySide6==6.11.0`, `qt-material`
- **Dependencies**: `requests`, `Flask`, `httpx`, `defusedxml`, `je_action_core` (the executor core shared with LoadDensity, MailThunder and FileAutomation)
- **Optional GUI**: `PySide6==6.11.2`

## Build & Test Commands

Expand Down Expand Up @@ -39,8 +39,8 @@ je_api_testka/
│ ├── assert_result/ # Strategy pattern - response validation (JSON Schema, JSONPath, snapshots)
│ ├── callback/ # Observer pattern - post-request callbacks
│ ├── executor/ # Command pattern - JSON keyword-driven actions (AT_* commands)
│ ├── generate_report/ # Template Method - HTML/JSON/XML/JUnit/Allure/Markdown reports
│ ├── mock_server/ # Flask-based mock server
│ ├── generate_report/ # Template Method - HTML/JSON/XML/JUnit/Allure/Markdown reports, latency trends
│ ├── mock_server/ # Flask mock server plus WebSocket and gRPC mocks
│ ├── socket_server/ # TCP remote automation server
│ ├── project/ # Factory pattern - project scaffolding
│ ├── json/, xml/ # JSON and XML I/O utilities
Expand All @@ -53,11 +53,12 @@ je_api_testka/
│ └── exception/ # Custom exception hierarchy
├── data/ # Variable store, templates, env profiles, fake data
├── connection/ # Connection options, DNS override, record/replay cassettes
├── diff/, spec/ # Response and contract diff, SLA checks; schema inference, OpenAPI export
├── diff/, spec/ # Response and contract diff, SLA checks; schema inference, OpenAPI export, test-as-spec loop
├── contract/ # Pact-style consumer contracts, provider verification, OpenAPI check
├── security/ # Auth helpers, header scan, fuzzing, pip-audit wrapper
├── runner/ # Parallel runner, tag filter, dependency ordering
├── integrations/ # cURL and HAR import, webhook notify, GitHub PR comment
├── ai/ # Pluggable text-completion backend (no-op by default)
├── integrations/ # cURL and HAR import, webhook notify, GitHub PR comment, LoadDensity bridge
├── ai/ # Pluggable text-completion backend (no-op by default; Anthropic reference backend)
├── cli/ # Subcommand CLI (`apitestka`)
├── mcp_server/ # MCP stdio server (`apitestka-mcp`)
├── pytest_plugin/ # pytest fixtures via the pytest11 entry point
Expand Down Expand Up @@ -211,6 +212,7 @@ Workspace rule shared by every repository under `D:\Codes` (full text: `D:\Codes
- Stage only the files that stage touched (`git add <path>`, never `git add -A`), follow this file's commit-message rules, and never add AI attribution.
- Committing is not pushing: push or open a PR only as this project's branch flow says or when asked.
- **Commit and push frequently.** After each big feature — a self-contained stage that passes this project's checks — commit and push to the remote; do not pile up a large batch of work before committing or pushing. Smaller batches collide less with other sessions, let CI catch problems earlier, and are easier to revert. Follow this project's normal branch flow (usually `dev`).
- **SonarCloud / Codacy findings.** When a PR or commit fails a SonarCloud or Codacy check, look the findings up through their APIs instead of guessing. The keys are in environment variables: `SonarCloudToken` (SonarCloud, e.g. `curl -s -u "$SonarCloudToken:" "https://sonarcloud.io/api/issues/search?componentKeys=<key>&pullRequest=<n>&resolved=false"`) and `CODACY_PROJECT_TOKEN` (a Codacy project token, valid only for its own project: any other repository answers "Bad credentials", so for a public repository query `https://app.codacy.com/api/v3/analysis/organizations/gh/<org>/repositories/<repo>/pull-requests/<n>/issues?status=new` without a key). **Never reveal a key or any personal credential while doing so**: refer to the variables by name only, never echo or print their values, and never put them in files, commit messages, PR or issue text, logs, or any output that leaves the machine.
- **`progress.md`** (repository root, tracked) holds outstanding work only: no finished items, no history, no rules.
- **`docs/updates/`** records finished work: one batch file per month (`YYYY-MM.md`), one entry per piece of work headed `## U-YYYYMMDD-NN · date · title · #tags`, and an index with query commands in `docs/updates/README.md`. When a `progress.md` item is done, delete it and add a `#done` entry plus its index row in the same commit.
- **`architecture.md`** (repository root) is the short architecture overview: layers, entry points, main flows, extension points, cross-project boundaries. Update it in the same commit whenever a change alters any of those.
Expand All @@ -224,6 +226,7 @@ Workspace rule shared by every repository under `D:\Codes` (full text: `D:\Codes
- **Do NOT mention any AI tools, assistants, or co-authors in commit messages**
- **No `Co-Authored-By` lines referencing AI in commits**
- Focus on what changed and why, not how it was written
- Both branches publish to PyPI from CI: a push to `main` releases `je_api_testka` (`publish.yml`), and a push to `dev` that passes the tests and changes what the package ships releases `je_api_testka_dev` (the `publish-dev` job of `ci.yml`, `scripts/dev_release.py`). Never bump a version by hand; the version in `dev.toml` is only a floor
- Examples:
- `feat: add HTTP/2 multiplexing support for httpx async backend`
- `fix: prevent XXE injection in XML report parser`
Expand Down
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The source distribution carries no tests. Without this line setuptools adds test/test*.py by default.
# Keep it last: a later include, recursive-include, global-include or graft could bring the directory back
# (test/test_utils/test_sdist_manifest.py).
prune test
Loading
Loading