diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml new file mode 100644 index 0000000..a38e141 --- /dev/null +++ b/.github/workflows/release-binaries.yml @@ -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 }} diff --git a/.github/workflows/trigger-docs-release.yml b/.github/workflows/trigger-docs-release.yml new file mode 100644 index 0000000..3cd5582 --- /dev/null +++ b/.github/workflows/trigger-docs-release.yml @@ -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 }} diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index ce9ba51..b89c987 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -3,24 +3,39 @@ ## 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 @@ -28,8 +43,8 @@ twine upload dist/* 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 diff --git a/ExampleConfiguration/json_config.json b/ExampleConfiguration/json_config.json index 327a62f..681d52e 100644 --- a/ExampleConfiguration/json_config.json +++ b/ExampleConfiguration/json_config.json @@ -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": { diff --git a/ExampleConfiguration/pyproject_example.toml b/ExampleConfiguration/pyproject_example.toml index 1ab38c7..058701b 100644 --- a/ExampleConfiguration/pyproject_example.toml +++ b/ExampleConfiguration/pyproject_example.toml @@ -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[^.]+?)\s*\[Robot-Library\].*'] resource-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Resource\].*'] library-root = ["RF", "RF-Library"] @@ -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] diff --git a/ExampleConfiguration/toml_config.toml b/ExampleConfiguration/toml_config.toml index 1ab38c7..058701b 100644 --- a/ExampleConfiguration/toml_config.toml +++ b/ExampleConfiguration/toml_config.toml @@ -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[^.]+?)\s*\[Robot-Library\].*'] resource-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Resource\].*'] library-root = ["RF", "RF-Library"] @@ -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] diff --git a/docs/configuration/cli_options.md b/docs/configuration/cli_options.md index 3b91e06..7ab53c4 100644 --- a/docs/configuration/cli_options.md +++ b/docs/configuration/cli_options.md @@ -2,111 +2,130 @@ sidebar_position: 2 --- -# CLI Options Reference +# Command-Line Usage -Complete reference for all command-line options available in TestBench2RobotFramework. +This page explains how the command line is structured and how to write option +values. It does **not** repeat every option — each one, with its accepted values +and default, lives in the [Configuration Reference](./overview.md). -## Global Options +## Structure of a command -These options are available for all commands: +Everything runs through two subcommands: -| Option | Description | -|--------|-------------| -| `--help` | Displays the help message and exits. | -| `--version` | Writes the TestBench2RobotFramework, Robot Framework and Python version to console. | -| `-c`, `--config PATH` | Path to a configuration file for TestBench2RobotFramework. | +```bash +testbench2robotframework generate-tests [OPTIONS] +testbench2robotframework fetch-results [OPTIONS] +``` -## generate-tests Options +- `generate-tests` takes one positional argument: the TestBench JSON report + (a directory or `.zip`). +- `fetch-results` takes two: the Robot Framework `output.xml` first, then the + TestBench report the suites were generated from. -Options specific to the `generate-tests` subcommand: +The short entry point `tb2robot` is an alias for `testbench2robotframework`. -### Output Options +Two options work on the group itself, before the subcommand: -| Option | Type | Description | -|--------|------|-------------| -| `-d`, `--output-directory PATH` | Path | Directory or ZIP archive containing the generated test suites. | -| `--clean` | Flag | Deletes all files present in the output-directory before new test suites are created. | +```bash +testbench2robotframework --help # or -h +testbench2robotframework --version # or -v — tool, Robot Framework, Python and supported TestBench versions +``` -### Keyword & Logging Options +Each subcommand also has its own `--help`: -| Option | Type | Description | -|--------|------|-------------| -| `--compound-keyword-logging` | Choice | Mode for logging compound keywords. Options: `GROUP`, `COMMENT`, or `NONE`. | -| `--fully-qualified` | Flag | Calls Robot Framework keywords by their fully qualified names in the generated test suites. | -| `--log-suite-numbering` | Flag | Enables logging of the test suite numbering. | -| `--metadata TEXT` | Text | Add extra metadata to the settings of the generated Robot Framework test suite. Provide entries as `key:value` pairs. | +```bash +testbench2robotframework generate-tests --help +testbench2robotframework fetch-results --help +``` -### Resource & Library Options +## Writing option values -| Option | Type | Description | -|--------|------|-------------| -| `--resource-directory PATH` | Path | Directory containing the Robot Framework resource files. | -| `--resource-directory-regex TEXT` | Regex | Regex that can be used to identify the TestBench Subdivision that corresponds to the resource-directory. Resources will be imported relative to this subdivision based on the test elements structure in TestBench. | -| `--library-regex TEXT` | Regex | Regular expression used to identify TestBench subdivisions corresponding to Robot Framework libraries. | -| `--library-root TEXT` | Text | TestBench root subdivision whose direct children correspond to Robot Framework libraries. | -| `--resource-regex TEXT` | Regex | Regular expression used to identify TestBench subdivisions corresponding to Robot Framework resources. | -| `--resource-root TEXT` | Text | TestBench root subdivision whose direct children correspond to Robot Framework resources. | -| `--library-mapping TEXT` | Text | Library import statement to use when a keyword from the specified TestBench subdivision is encountered. | -| `--resource-mapping TEXT` | Text | Resource import statement to use when a keyword from the specified TestBench subdivision is encountered. | +The option name on the command line is the same as in a configuration file; only +the syntax differs. Every option belongs to one of these shapes. -## fetch-results Options +**Text and paths** take a value: -Options specific to the `fetch-results` subcommand: +```bash +--output-directory ./Generated +--phase-pattern "{testcase} : Phase {index}/{length}" +``` -| Option | Type | Description | -|--------|------|-------------| -| `-d`, `--output-directory PATH` | Path | Path to the directory or ZIP file where the updated TestBench JSON report (with results) should be saved. | +**Simple flags** are either present (true) or absent (false): -## Usage Examples +```bash +--fully-qualified --include-blocked --log-suite-numbering +``` -### Display Help +**The clean flag is a pair.** `--clean` and `--no-clean` are two spellings of one +tri-state option. Give neither and the configuration file decides (default: +clean); give one to force it: -```powershell -testbench2robotframework --help -testbench2robotframework generate-tests --help -testbench2robotframework fetch-results --help +```bash +--clean # remove previously generated suites first +--no-clean # keep them and generate additively ``` -### Check Version +**List options are repeatable** — pass the flag once per value: -```powershell -testbench2robotframework --version +```bash +--library-root RF --library-root RF-Library +--library-regex '(?:.*\.)?(?P[^.]+?)\s*\[Robot-Library\].*' ``` -### Generate Tests with Multiple Options +**Mapping options take a `name:value` pair** and are also repeatable. The part +before the first colon is the key; everything after it is the value (so the value +may itself contain colons): -```powershell -testbench2robotframework generate-tests \ - --clean \ - -d ./Generated \ - --compound-keyword-logging GROUP \ - --fully-qualified \ - --log-suite-numbering \ - my_report.json +```bash +--library-mapping "RoboSAPiens:RoboSAPiens language=de" +--metadata "Responsible:Jane Doe" --metadata "Environment:staging" ``` -### Fetch Results with Custom Output +A value that is not in `name:value` form is rejected with a clear error. -```powershell -testbench2robotframework fetch-results \ - -d ./updated_reports \ - output.xml \ - testbench_report.json -``` +## Choosing an explicit configuration file -### Using Configuration File +`-c` / `--config` points at one TOML **or** JSON file and **replaces** the +automatic `pyproject.toml` / `robot.toml` / `.robot.toml` lookup — when it is +given, those project files are ignored: -```powershell -testbench2robotframework generate-tests -c config.toml my_report.json +```bash +testbench2robotframework generate-tests -c ./my-config.toml my_report.zip ``` -## Option Priority +How the automatic files are found and merged, and how a config file is written, +is covered in [Configuration Files](./pyproject_config.md). + +## Precedence + +Command-line options sit at the top of the precedence chain: they override the +configuration files, which override the built-in defaults. The full order is in +[Precedence](./overview.md#precedence). -When the same option is specified in multiple places, the priority order is: +## Examples -1. **Command-line options** (highest priority) -2. **Workspace-local `.robot.toml`** -3. **Project `robot.toml` or `pyproject.toml`** -4. **Default values** (lowest priority) +Generate into a chosen directory, keeping existing suites, with grouped compound +keywords and qualified keyword names: +```bash +testbench2robotframework generate-tests \ + -d ./Generated \ + --no-clean \ + --compound-keyword-logging GROUP \ + --fully-qualified \ + my_report.zip +``` + +Write the results of a run back into a new report, overwriting the protocol +instead of merging: + +```bash +testbench2robotframework fetch-results \ + -d ./updated_report.zip \ + --no-merge-protocol \ + ./results/output.xml \ + my_report.zip +``` +For what each option does and its accepted values, see the +[Configuration Reference](./overview.md). diff --git a/docs/configuration/overview.md b/docs/configuration/overview.md index 7dd63b5..dda8302 100644 --- a/docs/configuration/overview.md +++ b/docs/configuration/overview.md @@ -2,92 +2,554 @@ sidebar_position: 1 --- -# Configuration Overview +# Configuration Reference -TestBench2RobotFramework offers flexible configuration options to customize the behavior of test generation and result fetching. +This page lists **every** configuration option: where it applies, its accepted +values, its default, and how to set it on the command line and in a configuration +file. -## Configuration Methods +## How to configure -You can configure TestBench2RobotFramework using three different methods: +You can configure TestBench2RobotFramework in three ways, and they can be +combined: -### 1. Command-Line Options +1. **Command-line options** — passed directly to a command, best for one-off runs + and overrides. +2. **Configuration files** — `pyproject.toml`, `robot.toml` or a workspace-local + `.robot.toml`, best for reusable, team-wide settings. All options live under a + `[tool.testbench2robotframework]` section. +3. **A `-c` / `--config` file** — an explicit TOML **or** JSON file. -Pass options directly when running commands: +### Precedence -```powershell -testbench2robotframework generate-tests --clean -d ./Generated my_report.json +When the same option is set in several places, the last one wins: + +1. Built-in defaults +2. `pyproject.toml` +3. `robot.toml` +4. `.robot.toml` +5. Command-line options + +The three automatic files are searched upwards from the current working +directory and merged **per top-level key** (a whole table like `library-mapping` +is replaced, not merged entry by entry). + +:::caution +`-c` / `--config` **replaces** the automatic file lookup. When it is given, only +that one file is read and any `pyproject.toml` / `robot.toml` / `.robot.toml` in +the project is ignored. A TOML file needs the `[tool.testbench2robotframework]` +section; a JSON file holds the keys directly at the top level (see +[JSON configuration](./pyproject_config.md#json-configuration)). +::: + +### How an option maps between CLI and file + +The option name is the same in both places; only the syntax differs by type: + +| Type | Command line | Configuration file (TOML) | +|------|--------------|---------------------------| +| Text / number | `--phase-pattern "..."` | `phase-pattern = "..."` | +| Boolean flag | `--fully-qualified` (present = true) | `fully-qualified = true` | +| Boolean pair | `--clean` / `--no-clean` | `clean = true` / `false` | +| List (repeatable) | `--library-root RF --library-root RF-Library` | `library-root = ["RF", "RF-Library"]` | +| Mapping | `--library-mapping "name:import"` (repeatable) | a `[tool.testbench2robotframework.library-mapping]` table | + +Options **not** available on the command line can only be set in a configuration +file. This is noted per option below. + +--- + +## All options at a glance + +`G` = affects `generate-tests`, `F` = affects `fetch-results`. + +| Option | CLI | File | Command | Values (default) | +|--------|:---:|:----:|:-------:|------------------| +| [`output-directory`](#output-directory) | `-d` | ✅ | G · F | path or `.zip` (`{root}/Generated`) | +| [`clean`](#clean) | `--clean`/`--no-clean` | ✅ | G | bool (`true`) | +| [`clean-mode`](#clean-mode) | — | ✅ | G | `GENERATED` \| `ALL` (`GENERATED`) | +| [`create-output-zip`](#create-output-zip) | — | ✅ | G | bool (`false`) | +| [`fully-qualified`](#fully-qualified) | `--fully-qualified` | ✅ | G | bool (`false`) | +| [`log-suite-numbering`](#log-suite-numbering) | `--log-suite-numbering` | ✅ | G | bool (`false`) | +| [`include-blocked`](#include-blocked) | `--include-blocked` | ✅ | G | bool (`false`) | +| [`compound-keyword-logging`](#compound-keyword-logging) | `--compound-keyword-logging` | ✅ | G | `GROUP` \| `COMMENT` \| `NONE` (`GROUP`) | +| [`testcase-splitting-regex`](#testcase-splitting-regex) | — | ✅ | G | regex (`.*StopWithRestart.*`) | +| [`phase-pattern`](#phase-pattern) | — | ✅ | G · F | pattern (`{testcase} : Phase {index}/{length}`) | +| [`library-regex`](#library-regex--resource-regex) | `--library-regex` | ✅ | G | list of regex (see below) | +| [`resource-regex`](#library-regex--resource-regex) | `--resource-regex` | ✅ | G | list of regex (see below) | +| [`library-root`](#library-root--resource-root) | `--library-root` | ✅ | G | list (`["RF", "RF-Library"]`) | +| [`resource-root`](#library-root--resource-root) | `--resource-root` | ✅ | G | list (`["RF-Resource"]`) | +| [`resource-directory`](#resource-directory) | `--resource-directory` | ✅ | G | path (empty) | +| [`resource-directory-regex`](#resource-directory-regex) | `--resource-directory-regex` | ✅ | G | regex (`.*\[Robot-Resources\].*`) | +| [`library-mapping`](#library-mapping--resource-mapping) | `--library-mapping` | ✅ | G | mapping (`{}`) | +| [`resource-mapping`](#library-mapping--resource-mapping) | `--resource-mapping` | ✅ | G | mapping (`{}`) | +| [`forced-import`](#forced-import) | — | ✅ | G | table of lists (`{}`) | +| [`metadata`](#metadata) | `--metadata` | ✅ | G | mapping (`{}`) | +| [`merge-protocol`](#merge-protocol) | `--no-merge-protocol` | ✅ | F | bool (`true`) | +| [`keyword-comment-style`](#keyword-comment-style) | — | ✅ | F | `STRUCTURED` \| `FLAT` (`STRUCTURED`) | +| [`keyword-comment-max-depth`](#keyword-comment-max-depth) | — | ✅ | F | int (`5`) | +| [`keyword-comment-max-rows`](#keyword-comment-max-rows) | — | ✅ | F | int, `0` = no limit (`300`) | +| [`keyword-comment-log-level`](#keyword-comment-log-level) | — | ✅ | F | `TRACE`…`FAIL` (`TRACE`) | +| [`reference-behaviour`](#reference-behaviour) | — | ✅ | F | `ATTACHMENT` \| `REFERENCE` \| `NONE` (`ATTACHMENT`) | +| [`attachment-conflict-behaviour`](#attachment-conflict-behaviour) | — | ✅ | F | `ERROR` \| `USE_NEW` \| `USE_EXISTING` \| `RENAME_NEW` (`USE_EXISTING`) | +| [`console-logging`](#console-logging--file-logging) | — | ✅ | G · F | table | +| [`file-logging`](#console-logging--file-logging) | — | ✅ | G · F | table | + +--- + +## Output + +### `output-directory` + +Where generated suites (or, for `fetch-results`, the updated report) are written. +A plain path is treated as a directory; a `.zip` path packs the output into a ZIP +archive instead. The placeholder `{root}` at the start is replaced by the +absolute path of the directory the command runs in. + +- **Values:** a directory path or a `.zip` file path. Default: `{root}/Generated`. +- **CLI:** `-d` / `--output-directory`. + +```bash +testbench2robotframework generate-tests -d ./Generated my_report.zip +testbench2robotframework generate-tests -d ./suites.zip my_report.zip +``` +```toml +output-directory = "{root}/Generated" ``` -✅ **Best for:** Quick, one-time runs and overriding specific settings +### `create-output-zip` -### 2. Configuration Files +For `generate-tests` only: in addition to the normal directory output, also +produce a ZIP archive of the generated suites next to it. Independent of using a +`.zip` `output-directory`. **Configuration file only.** -Store settings in configuration files for reusable configurations: +- **Values:** `true` / `false`. Default: `false`. -- `pyproject.toml` - Python project configuration -- `robot.toml` - Robot Framework specific configuration -- `.robot.toml` - Workspace-local configuration +```toml +create-output-zip = true +``` + +--- + +## Cleaning the output directory + +### `clean` -✅ **Best for:** Team projects, consistent settings, complex configurations +Whether previously generated suites are removed before generating. Cleaning is +**selective**: only `.robot` files that carry the generated +`Metadata UniqueID` marker are deleted, together with directories left empty by +that. Hand-written suites, resource files and any other content in the output +directory are kept. A `.zip` output target is removed as a whole. + +- **Values:** `true` / `false`. Default: `true` (in a configuration file). On the + command line, without either flag the configuration decides. +- **CLI:** the flag pair `--clean` / `--no-clean`. Use `--no-clean` to generate + additively (nothing is removed). + +```bash +testbench2robotframework generate-tests --clean my_report.zip # remove old generated suites first +testbench2robotframework generate-tests --no-clean my_report.zip # keep everything, add to it +``` +```toml +clean = true +``` -TestBench2RobotFramework will automatically detect and apply settings from these files when present. +### `clean-mode` -### 3. Mixed Approach +What `clean` removes. `GENERATED` (default) is the selective behaviour described +above. `ALL` restores the pre-2.0 behaviour of deleting the **entire** output +directory, including files this tool did not write — use it with care and point +`output-directory` at a directory that contains nothing else. **Configuration +file only**, deliberately without a CLI flag. -Combine both methods - command-line options override configuration file settings: +- **Values:** `GENERATED` \| `ALL`. Default: `GENERATED`. -```powershell -testbench2robotframework generate-tests -c config.toml --clean my_report.json +```toml +clean = true +clean-mode = "ALL" ``` -## Configuration Hierarchy +--- -When multiple configuration methods are used, settings are applied in the following order (later overrides earlier): +## Suite generation -1. Default values -2. `pyproject.toml` or `robot.toml` -3. `.robot.toml` (workspace-local) -4. Command-line options +### `fully-qualified` -## Common Configuration Options +Call Robot Framework keywords by their fully qualified name +(`Browser.Click`) instead of the plain keyword name. Use this when +two imported libraries or resources provide a keyword of the same name, to make +the generated calls unambiguous. -### Output Settings +- **Values:** `true` / `false`. Default: `false`. +- **CLI:** `--fully-qualified` (flag). -- `output-directory` - Where to save generated files or results -- `clean` - Delete existing files before generating new ones -- `fully-qualified` - Enable/disable fully qualified keyword names in generated test suites -- `compound-keyword-logging` - Control compound TestBench keyword logging (`GROUP`, `COMMENT`, `NONE`) -- `log-suite-numbering` - Enable/disable suite numbering in generated file names -- `testcase-splitting-regex` - Regular expression to split test cases at matching interactions -- `phase-pattern` - Pattern for naming test case phases when splitting +```bash +testbench2robotframework generate-tests --fully-qualified my_report.zip +``` +```toml +fully-qualified = true +``` -### Library & Resource Mapping +### `log-suite-numbering` -- `library-regex` - Pattern to identify TestBench subdivisions as libraries -- `resource-regex` - Pattern to identify TestBench subdivisions as resources -- `library-root` - Root subdivision for libraries -- `resource-root` - Root subdivision for resources -- `library-mapping` - Custom library import statements -- `resource-mapping` - Custom resource import statements -- `resource-directory` - Directory containing Robot Framework resource files -- `resource-directory-regex` - Regex to identify the TestBench subdivision corresponding to the resource directory +Keeps the TestBench numbering visible in the Robot Framework **suite name**. The +numbering always prefixes the generated file name; by default the prefix ends +with a double underscore (`01__Login.robot`), which Robot strips from the +displayed suite name. With this option the prefix uses a single underscore +(`01_Login.robot`), so the numbering stays part of the visible suite name. -### Metadata +- **Values:** `true` / `false`. Default: `false`. +- **CLI:** `--log-suite-numbering` (flag). -- `metadata` - Extra metadata key-value pairs added to generated test suite settings +```bash +testbench2robotframework generate-tests --log-suite-numbering my_report.zip +``` +```toml +log-suite-numbering = true +``` -### Forced Imports +### `include-blocked` -- `forced-import` - Force import of specific libraries, resources, or variables in every generated suite +By default, test elements whose TestBench execution status is `Blocked` are not +generated — blocked test cases are left out of their suite, a blocked test case +set produces no `.robot` file, and a blocked test theme drops its whole subtree. +Enable this option to generate them anyway. + +- **Values:** `true` / `false`. Default: `false`. +- **CLI:** `--include-blocked` (flag). + +```bash +testbench2robotframework generate-tests --include-blocked my_report.zip +``` +```toml +include-blocked = true +``` -### Attachment & Reference Handling +### `compound-keyword-logging` -- `reference-behaviour` - How to handle references (`ATTACHMENT`, `REFERENCE`, `NONE`) -- `attachment-conflict-behaviour` - How to handle attachment conflicts (`ERROR`, `USE_NEW`, `USE_EXISTING`, `RENAME_NEW`) +How compound (higher-level) TestBench keywords are represented in the generated +suite. `GROUP` wraps their child keywords in a Robot Framework `GROUP` block (this +needs Robot Framework 7.2+; on older versions it falls back to `COMMENT` with a +warning). `COMMENT` emits the compound keyword as a comment above its inlined +children. `NONE` inlines the children without any marker. -### Logging +- **Values:** `GROUP` \| `COMMENT` \| `NONE`. Default: `GROUP`. +- **CLI:** `--compound-keyword-logging`. + +```bash +testbench2robotframework generate-tests --compound-keyword-logging COMMENT my_report.zip +``` +```toml +compound-keyword-logging = "GROUP" +``` + +### `testcase-splitting-regex` + +A regular expression matched against the subdivision path of each interaction. An +interaction that matches **splits** the TestBench test case into several Robot +Framework tests at that point — useful for keywords that restart the system under +test. See [Test Case Splitting](../usage/generate_tests.md#test-case-splitting). +**Configuration file only.** + +- **Values:** a regular expression. Default: `.*StopWithRestart.*`. + +```toml +testcase-splitting-regex = ".*StopWithRestart.*" +``` + +### `phase-pattern` + +The naming pattern for the Robot Framework tests produced by test case splitting. +`{testcase}` is the test case unique ID, `{index}` the phase number and +`{length}` the total number of phases. `fetch-results` uses the **same** pattern +to recombine the phases into one TestBench result, so it must match the value used +for `generate-tests`. Affects both commands. **Configuration file only.** + +- **Values:** a pattern using `{testcase}`, `{index}`, `{length}`. + Default: `{testcase} : Phase {index}/{length}`. + +```toml +phase-pattern = "{testcase} : Phase {index}/{length}" +``` + +--- + +## Mapping keywords to libraries and resources + +These options control which Robot Framework `Library` / `Resource` imports the +generated suites receive. For the full picture of how to structure TestBench +subdivisions, see +[Modeling Keywords in TestBench](../usage/generate_tests.md#modeling-keywords-in-testbench). + +### `library-regex` / `resource-regex` + +Lists of regular expressions matched (case-insensitively) against the subdivision +path of a keyword to decide whether it belongs to a Robot Framework **library** +or **resource file**, and which name to import. Each pattern must mark the name +with a named group (`resourceName`, `libraryName` or `name`) or with exactly one +capture group; see +[Subdivision Patterns](./pyproject_config.md#subdivision-patterns) for the rules. +Invalid or ambiguous patterns are rejected at startup. + +- **Values:** a list of regular expressions. + `library-regex` default: `['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Library\].*']`. + `resource-regex` default: `['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Resource\].*']`. +- **CLI:** `--library-regex` / `--resource-regex`, repeatable. + +```bash +testbench2robotframework generate-tests --library-regex "(?P\w+) \[Lib\]" my_report.zip +``` +```toml +library-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Library\].*'] +resource-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Resource\].*'] +``` + +### `library-root` / `resource-root` + +An alternative to the regex conventions: root subdivisions whose **direct +children** are the library / resource names. A keyword under `RF.Browser` +becomes `Library Browser` when `RF` is a library root. + +- **Values:** a list of subdivision names. + `library-root` default: `["RF", "RF-Library"]`. `resource-root` default: + `["RF-Resource"]`. +- **CLI:** `--library-root` / `--resource-root`, repeatable. + +```bash +testbench2robotframework generate-tests --library-root RF --library-root RF-Library my_report.zip +``` +```toml +library-root = ["RF", "RF-Library"] +resource-root = ["RF-Resource"] +``` + +### `resource-directory` + +The base directory for generated `Resource` imports. `Common [Robot-Resource]` +becomes `/Common.resource`. It is **empty** by default, so +resources are imported by plain file name and resolved by Robot Framework +relative to each generated suite. Set an absolute location (e.g. `{root}/Resources`) +for a single fixed resource directory. The placeholders `{root}` and, in +`resource-mapping` values, `{resourceDirectory}` are substituted at the start of a +value. + +- **Values:** a directory path. Default: empty. +- **CLI:** `--resource-directory`. + +```bash +testbench2robotframework generate-tests --resource-directory "{root}/Resources" my_report.zip +``` +```toml +resource-directory = "{root}/Resources" +``` -- `console-logging` - Console output log level and format -- `file-logging` - File-based log level, format, and file name +### `resource-directory-regex` +A **marker** pattern locating the subdivision that corresponds to the resource +directory. Subdivisions between the match and the resource itself become +subdirectories of `resource-directory`. Unlike `library-regex`/`resource-regex`, +this pattern extracts no name and needs no capture groups; it is searched +(case-insensitively) within each path segment. An expression that does not compile +is rejected at startup. + +- **Values:** a regular expression. Default: `.*\[Robot-Resources\].*`. +- **CLI:** `--resource-directory-regex`. + +```toml +resource-directory-regex = ".*\\[Robot-Resources\\].*" +``` + +### `library-mapping` / `resource-mapping` + +Override the import statement produced for a matched library / resource name. Use +this to add library arguments, point a resource at a specific path, or import a +remote library. The key is the name as identified by the patterns/roots above; the +value is the full import statement (arguments separated by the usual Robot +Framework whitespace). `{root}` and `{resourceDirectory}` placeholders are +substituted. + +- **Values:** a mapping of name → import statement. Default: `{}`. +- **CLI:** `--library-mapping` / `--resource-mapping` as `"name:import"` pairs, + repeatable. + +```bash +testbench2robotframework generate-tests \ + --library-mapping "Browser:Browser timeout=10s" my_report.zip +``` +```toml +[tool.testbench2robotframework.library-mapping] +Browser = "Browser timeout=10s run_on_failure=Take Screenshot" +RoboSAPiens = "RoboSAPiens language=de" + +[tool.testbench2robotframework.resource-mapping] +Common = "{root}/shared/Common.resource" +MyOtherKeywords = "{resourceDirectory}/subdir/MyOtherKeywords.resource" +``` + +### `forced-import` + +Libraries, resources and variable files that are imported into **every** generated +suite, regardless of the keywords it uses. Useful for a project-wide variables +file or a library that is always needed. **Configuration file only.** + +- **Values:** a table with `libraries`, `resources` and `variables` lists. + Default: all empty. + +```toml +[tool.testbench2robotframework.forced-import] +libraries = ["Collections"] +resources = ["common.resource"] +variables = ["variables.py"] +``` + +### `metadata` + +Extra `Metadata` entries added to the settings of every generated suite. A value +may contain `{$tcs...}` placeholders that are evaluated against the TestBench test +case set model — e.g. `{$tcs.spec.responsible.name}` inserts the responsible +person. The names `UniqueID`, `Name` and `Numbering` are reserved (they are the +markers `fetch-results` matches on) and cannot be overridden. + +- **Values:** a mapping of metadata name → value. Default: `{}`. +- **CLI:** `--metadata` as `"key:value"` pairs, repeatable. + +```bash +testbench2robotframework generate-tests --metadata "Team:Payments" my_report.zip +``` +```toml +[tool.testbench2robotframework.metadata] +Team = "Payments" +Responsible = "{$tcs.spec.responsible.name}" +``` + +--- + +## Result write-back (`fetch-results`) + +### `merge-protocol` + +Whether results are **merged** into the `protocol.json` already contained in the +report. When merging, executions the current Robot run covers are replaced, +executions it does not cover are kept, and the verdicts of test case sets and test +themes are recomputed over the merged set. Disable it to overwrite the protocol +with only the current run's results. + +- **Values:** `true` / `false`. Default: `true`. +- **CLI:** `--no-merge-protocol` (turns merging off). + +```bash +testbench2robotframework fetch-results --no-merge-protocol output.xml my_report.zip +``` +```toml +merge-protocol = true +``` + +### `keyword-comment-style` + +How the execution comment of a keyword is rendered. `STRUCTURED` shows the whole +Robot Framework keyword structure (sub keywords, control structures, loop +iterations) with the log messages of each. `FLAT` writes the plain list of log +messages of earlier versions. **Configuration file only.** + +- **Values:** `STRUCTURED` \| `FLAT`. Default: `STRUCTURED`. + +```toml +keyword-comment-style = "STRUCTURED" +``` + +### `keyword-comment-max-depth` + +The nesting depth up to which the keyword structure is shown in a `STRUCTURED` +comment. Deeper keywords are folded away, but their **log messages are still +shown** — only the structure disappears, with a note naming the number of hidden +sub keywords. **Configuration file only.** + +- **Values:** an integer. Default: `5`. + +```toml +keyword-comment-max-depth = 5 +``` + +### `keyword-comment-max-rows` + +The maximum number of table rows per keyword comment. A comment that would exceed +it is truncated, ending with a `... truncated, see the Robot Framework log` note. +`0` disables the limit. **Configuration file only.** + +- **Values:** an integer, `0` = no limit. Default: `300`. + +```toml +keyword-comment-max-rows = 300 +``` + +### `keyword-comment-log-level` + +The lowest Robot Framework log level shown in a keyword comment, with Robot's own +threshold semantics: a message is shown when its level is at or above the +configured one. `TRACE` (the default) filters nothing. Note that `TRACE`/`DEBUG` +messages only exist in the results when the Robot run itself used +`--loglevel DEBUG`/`TRACE`. **Configuration file only.** + +- **Values:** `TRACE` \| `DEBUG` \| `INFO` \| `WARN` \| `ERROR` \| `FAIL`. + Default: `TRACE`. + +```toml +keyword-comment-log-level = "TRACE" +``` + +### `reference-behaviour` + +How references found in test messages (via `itb-reference:` markers) are handled +when writing results back. `ATTACHMENT` copies the referenced file into the report +as an attachment, `REFERENCE` stores it as a reference, `NONE` ignores references. +**Configuration file only.** + +- **Values:** `ATTACHMENT` \| `REFERENCE` \| `NONE`. Default: `ATTACHMENT`. + +```toml +reference-behaviour = "ATTACHMENT" +``` + +### `attachment-conflict-behaviour` + +What happens when an attachment with the same name already exists in the report. +`USE_EXISTING` keeps the existing file, `USE_NEW` replaces it, `RENAME_NEW` stores +the new file under a unique name, and `ERROR` aborts. **Configuration file only.** + +- **Values:** `ERROR` \| `USE_NEW` \| `USE_EXISTING` \| `RENAME_NEW`. + Default: `USE_EXISTING`. + +```toml +attachment-conflict-behaviour = "USE_EXISTING" +``` + +--- + +## Logging + +### `console-logging` / `file-logging` + +The log level and format of the tool's own console output and its optional log +file. Both apply to `generate-tests` and `fetch-results`. **Configuration file +only.** + +- **Values:** a table with `logLevel`, `logFormat` (and, for `file-logging`, + `fileName`). Console defaults to level `INFO`; file logging defaults to level + `DEBUG` and file `testbench2robotframework.log`. + +```toml +[tool.testbench2robotframework.console-logging] +logLevel = "INFO" +logFormat = "%(levelname)s: %(message)s" + +[tool.testbench2robotframework.file-logging] +logLevel = "DEBUG" +logFormat = "%(asctime)s - %(filename)s:%(lineno)d - %(levelname)8s - %(message)s" +fileName = "testbench2robotframework.log" +``` + +--- +See [Configuration Files](./pyproject_config.md) for how configuration files are +found, merged and written, and [Command-Line Usage](./cli_options.md) for how the +command line is structured. diff --git a/docs/configuration/pyproject_config.md b/docs/configuration/pyproject_config.md index cb3171a..6ac69f2 100644 --- a/docs/configuration/pyproject_config.md +++ b/docs/configuration/pyproject_config.md @@ -2,170 +2,216 @@ sidebar_position: 3 --- -# pyproject.toml Configuration +# Configuration Files -All CLI options available for `testbench2robotframework` can be defined in your `pyproject.toml` file, `robot.toml`, or a workspace-local `.robot.toml`. This offers a convenient way to store and reuse configuration settings, particularly in larger projects or automated environments. +A configuration file keeps your settings in one place so every run — locally and +in CI — behaves the same. This page explains **which files are read, how they are +found and merged, and how to write their values**. What each individual option +does lives in the [Configuration Reference](./overview.md); link into it rather +than memorising the keys. -## Basic Structure +## Which files are read -Add a `[tool.testbench2robotframework]` section to your `pyproject.toml`: +TestBench2RobotFramework reads its settings from three files, all sharing one +format: -```toml -[tool.testbench2robotframework] -# Your configuration options here -``` +| File | Purpose | +|------|---------| +| `pyproject.toml` | project-wide settings, alongside your other Python tooling | +| `robot.toml` | project-wide settings when you have no `pyproject.toml` | +| `.robot.toml` | workspace-local overrides, typically not committed | -## Complete Configuration Example +In all three, the settings live under a `[tool.testbench2robotframework]` section. -Here's a comprehensive example with all available options: +Alternatively, point `-c` / `--config` at one explicit file (TOML **or** JSON). +That **replaces** the automatic lookup below — see +[Command-Line Usage](./cli_options.md#choosing-an-explicit-configuration-file) +and [JSON configuration](#json-configuration). -```toml -[tool.testbench2robotframework] -library-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Library\].*'] -resource-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Resource\].*'] -library-root = ["RF", "RF-Library"] -resource-root = ["RF-Resource"] -fully-qualified = false -output-directory = "{root}/Generated" -log-suite-numbering = false -clean = true -compound-keyword-logging = "GROUP" -resource-directory = "{root}/Resources" -resource-directory-regex = ".*\\[Robot-Resources\\].*" -reference-behaviour = "ATTACHMENT" -attachment-conflict-behaviour = "USE_EXISTING" -testcase-splitting-regex = ".*StopWithRestart.*" -phase-pattern = "{testcase} : Phase {index}/{length}" +## Lookup and merge strategy -[tool.testbench2robotframework.metadata] -# Example: MyKey = "my value" +Each of the three file names is searched for **upwards** from the current working +directory: the tool walks from the directory it runs in through its parent +directories and uses the first match of each name. This lets a nested project +directory inherit a `pyproject.toml` that sits at the repository root. -[tool.testbench2robotframework.library-mapping] -SeleniumLibrary = "SeleniumLibrary timeout=10 implicit_wait=1 run_on_failure=Capture Page Screenshot" -SuperRemoteLibrary = "Remote http://127.0.0.1:8270 WITH NAME SuperRemoteLibrary" +When more than one file is found, their `[tool.testbench2robotframework]` sections +are merged **per top-level key** in this order, the later file winning: -[tool.testbench2robotframework.resource-mapping] -MyKeywords = "{root}/../MyKeywords.resource" -MyOtherKeywords = "{resourceDirectory}/subdir/MyOtherKeywords.resource" - -[tool.testbench2robotframework.forced-import] -libraries = ["test.py"] -resources = [] -variables = [] - -[tool.testbench2robotframework.console-logging] -logLevel = "INFO" -logFormat = "%(levelname)s: %(message)s" - -[tool.testbench2robotframework.file-logging] -logLevel = "DEBUG" -logFormat = "%(asctime)s - %(filename)s:%(lineno)d - %(levelname)8s - %(message)s" -fileName = "testbench2robotframework.log" +``` +built-in defaults → pyproject.toml → robot.toml → .robot.toml → CLI options ``` -## Configuration Sections +:::caution +Merging is per top-level key, not deep. A whole table such as `library-mapping` is +replaced as a unit — if `.robot.toml` defines `[tool.testbench2robotframework.library-mapping]`, +it supersedes the entire mapping from `pyproject.toml` rather than adding to it. +::: -### Main Configuration +The complete precedence order, including the command line, is in +[Precedence](./overview.md#precedence). -The main `[tool.testbench2robotframework]` section contains general settings: +## TOML value syntax + +Each option type is written a particular way in TOML: ```toml [tool.testbench2robotframework] + +# text / paths — quoted strings output-directory = "{root}/Generated" -clean = true -fully-qualified = false -log-suite-numbering = false -compound-keyword-logging = "GROUP" -testcase-splitting-regex = ".*StopWithRestart.*" phase-pattern = "{testcase} : Phase {index}/{length}" -``` -### Metadata +# booleans +clean = true +fully-qualified = false -Add custom metadata to the settings of generated Robot Framework test suites: +# integers +keyword-comment-max-depth = 5 -```toml -[tool.testbench2robotframework.metadata] -MyMetadata = "some value" +# lists — for repeatable options such as the roots and regex patterns +library-root = ["RF", "RF-Library"] +library-regex = ['(?:.*\.)?(?P[^.]+?)\s*\[Robot-Library\].*'] ``` -### Library Mapping +:::tip +Write regular expressions as **single-quoted** TOML strings (`'...'`). In a +single-quoted string a backslash is literal, so a pattern like +`\s*\[Robot-Library\]` needs no doubling. In a double-quoted string you would have +to escape every backslash (`"\\s*\\[Robot-Library\\]"`). +::: -Define custom import statements for libraries: +Mappings and other grouped settings are their own **sub-tables**, named +`[tool.testbench2robotframework.