Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
122 changes: 122 additions & 0 deletions .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Release binaries

on:
release:
types:
- published

permissions:
contents: write

defaults:
run:
shell: bash

jobs:
build_wheel:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install build tooling
run: |
python -m pip install --upgrade pip
pip install flit

- name: Build wheel
run: flit build --format wheel

- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: wheel-dist
path: dist/*.whl

build_binaries:
needs: build_wheel
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux
artifact_name: testbench2robotframework-linux
binary_name: testbench2robotframework
- os: macos-latest
platform: macos
artifact_name: testbench2robotframework-macos
binary_name: testbench2robotframework
- os: windows-latest
platform: windows
artifact_name: testbench2robotframework-windows.exe
binary_name: testbench2robotframework.exe
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Install runtime dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller .

- name: Build executable
run: |
ICON_PATH=$(python -c "from pathlib import Path; print(Path('pyinstaller/imbusTB.ico').resolve())")
pyinstaller pyinstaller/run.py \
-i "$ICON_PATH" \
--onefile \
--name testbench2robotframework \
--clean \
-y \
--distpath "pyinstaller/dist/${{ matrix.platform }}" \
--workpath "pyinstaller/build/${{ matrix.platform }}" \
--specpath "pyinstaller/build/${{ matrix.platform }}"

- name: Collect build output
run: |
mkdir -p release
cp "pyinstaller/dist/${{ matrix.platform }}/${{ matrix.binary_name }}" "release/${{ matrix.artifact_name }}"

- name: Upload executable artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact_name }}
path: release/${{ matrix.artifact_name }}

publish_release:
needs:
- build_wheel
- build_binaries
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true

- name: List assets
run: ls -R release-assets

- name: Upload assets to release
uses: softprops/action-gh-release@v2
with:
files: |
release-assets/*.whl
release-assets/testbench2robotframework-linux
release-assets/testbench2robotframework-macos
release-assets/testbench2robotframework-windows.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49 changes: 49 additions & 0 deletions .github/workflows/trigger-docs-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Trigger Documentation Release

on:
release:
types: [published]

jobs:
trigger-docs:
name: Trigger ecosystem docs versioning
runs-on: ubuntu-latest
steps:
- name: Derive tool metadata
id: meta
run: |
# Tool ID = repository name (must match tools.config.json in ecosystem-docs)
TOOL_ID="${{ github.event.repository.name }}"

# Version = release tag, strip leading 'v' if present
RAW_TAG="${{ github.event.release.tag_name }}"
VERSION="${RAW_TAG#v}"

echo "tool_id=${TOOL_ID}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=${RAW_TAG}" >> $GITHUB_OUTPUT

echo "Tool: ${TOOL_ID}"
echo "Version: ${VERSION}"
echo "Tag: ${RAW_TAG}"

- name: Trigger ecosystem documentation workflow
run: |
jq -n \
--arg tool_id "${{ steps.meta.outputs.tool_id }}" \
--arg version "${{ steps.meta.outputs.version }}" \
--arg tag "${{ steps.meta.outputs.tag }}" \
--arg source_repo "${{ github.repository }}" \
'{
event_type: "tool-docs-release",
client_payload: {
tool_id: $tool_id,
version: $version,
tag: $tag,
source_repo: $source_repo
}
}' | gh api repos/${{ github.repository_owner }}/testbench-ecosystem-documentation/dispatches \
--method POST \
--input -
env:
GH_TOKEN: ${{ secrets.ECOSYSTEM_DOCS_TOKEN }}
51 changes: 33 additions & 18 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,48 @@
## Setting up project for the first time

1. Create venv and activate it:
```bash
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\scripts\activate # Windows
```
```bash
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\scripts\activate # Windows
```
2. Install project with dev dependencies:
```bash
pip install -e .[dev]
```
```bash
pip install -e .[dev]
```

## Building and publishing
## Release process

```bash
check-manifest --update
python -m build
twine check dist/*
twine upload dist/*
```
This project is published with `flit`.

1. Prepare the release
1. Make sure you are on the correct branch and your working tree is clean.
2. Update the version in `testbench2robotframework/__init__.py` (`__version__`).
3. Commit the version change (and other release-related updates).
2. Build artifacts locally (without upload)
```bash
flit build
```
This creates source and wheel distributions in `dist/` so you can verify the build output.
3. Publish to PyPI
```bash
flit publish
```
`flit publish` builds, validates, and uploads the package.
4. Verify the release
1. Confirm the new version is visible on PyPI.
2. Create and push a git tag for the released version (for example `v1.1.0`).

If you only need to validate packaging locally, use `flit build` and skip the publish step.

## Updating the data model

`testbench2robotframework/model.py` is generated from the TestBench OpenAPI spec using [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator).

1. Download the OpenAPI YAML from the TestBench Swagger documentation (e.g. `openapi.yml`).
2. Generate the model (settings are in `pyproject.toml` under `[tool.datamodel-codegen]`):
```bash
invoke generate-model --input openapi.yml
```
```bash
invoke generate-model --input openapi.yml
```
This runs `datamodel-codegen` and injects `__VERSION__` from the spec's `info.version` field into `model.py`.
3. Review the generated file
2 changes: 1 addition & 1 deletion ExampleConfiguration/json_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"phase-pattern": "{testcase} : Phase {index}/{length}",
"metadata": {},
"library-mapping": {
"SeleniumLibrary": "SeleniumLibrary timeout=10 implicit_wait=1 run_on_failure=Capture Page Screenshot",
"Browser": "Browser timeout=10s run_on_failure=Take Screenshot",
"SuperRemoteLibrary": "Remote http://127.0.0.1:8270 WITH NAME SuperRemoteLibrary"
},
"resource-mapping": {
Expand Down
9 changes: 8 additions & 1 deletion ExampleConfiguration/pyproject_example.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[tool.testbench2robotframework]
# 'library-regex' and 'resource-regex' say which TestBench subdivisions are
# Robot Framework libraries or resources, and which part of the subdivision path
# is the name to import. Mark that part in one of two ways:
# 1. a named group - 'resourceName', 'libraryName' or 'name' (checked in that
# order). It wins no matter where it sits or how many groups the pattern has.
# 2. or exactly one capture group, which is then taken as the name.
# A pattern with several groups and none of those names is rejected on startup.
library-regex = ['(?:.*\.)?(?P<resourceName>[^.]+?)\s*\[Robot-Library\].*']
resource-regex = ['(?:.*\.)?(?P<resourceName>[^.]+?)\s*\[Robot-Resource\].*']
library-root = ["RF", "RF-Library"]
Expand All @@ -16,7 +23,7 @@ reference-behaviour = "ATTACHMENT"
attachment-conflict-behaviour = "USE_EXISTING"

[tool.testbench2robotframework.library-mapping]
SeleniumLibrary = "SeleniumLibrary timeout=10 implicit_wait=1 run_on_failure=Capture Page Screenshot"
Browser = "Browser timeout=10s run_on_failure=Take Screenshot"
SuperRemoteLibrary = "Remote http://127.0.0.1:8270 WITH NAME SuperRemoteLibrary"

[tool.testbench2robotframework.resource-mapping]
Expand Down
9 changes: 8 additions & 1 deletion ExampleConfiguration/toml_config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[tool.testbench2robotframework]
# 'library-regex' and 'resource-regex' say which TestBench subdivisions are
# Robot Framework libraries or resources, and which part of the subdivision path
# is the name to import. Mark that part in one of two ways:
# 1. a named group - 'resourceName', 'libraryName' or 'name' (checked in that
# order). It wins no matter where it sits or how many groups the pattern has.
# 2. or exactly one capture group, which is then taken as the name.
# A pattern with several groups and none of those names is rejected on startup.
library-regex = ['(?:.*\.)?(?P<resourceName>[^.]+?)\s*\[Robot-Library\].*']
resource-regex = ['(?:.*\.)?(?P<resourceName>[^.]+?)\s*\[Robot-Resource\].*']
library-root = ["RF", "RF-Library"]
Expand All @@ -16,7 +23,7 @@ reference-behaviour = "ATTACHMENT"
attachment-conflict-behaviour = "USE_EXISTING"

[tool.testbench2robotframework.library-mapping]
SeleniumLibrary = "SeleniumLibrary timeout=10 implicit_wait=1 run_on_failure=Capture Page Screenshot"
Browser = "Browser timeout=10s run_on_failure=Take Screenshot"
SuperRemoteLibrary = "Remote http://127.0.0.1:8270 WITH NAME SuperRemoteLibrary"

[tool.testbench2robotframework.resource-mapping]
Expand Down
Loading