-
Notifications
You must be signed in to change notification settings - Fork 17
docs: add Sphinx documentation site with Bazel #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
clanghans
wants to merge
4
commits into
eclipse-score:main
Choose a base branch
from
etas-contrib:feature/docs-as-code-initial
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
a05e144
build(docs): add score_docs_as_code dep and docs() target
clanghans defaf01
docs: add Sphinx documentation site
clanghans 9f0d3d0
ci(docs): add docs verify and GitHub Pages workflow
clanghans c1f0674
Merge branch 'main' into feature/docs-as-code-initial
clanghans File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
| name: Verify and Build Docs | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, reopened, synchronize] | ||
| push: | ||
| branches: | ||
| - main | ||
| merge_group: | ||
| types: [checks_requested] | ||
| release: | ||
|
AlexanderLanin marked this conversation as resolved.
|
||
| types: [created] | ||
|
|
||
| jobs: | ||
| docs-verify: | ||
|
clanghans marked this conversation as resolved.
|
||
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | ||
| uses: eclipse-score/cicd-workflows/.github/workflows/docs-verify.yml@c1c90b1a82a1fab0fc202979dde6686b2162d5a8 # v0.0.0 | ||
| permissions: | ||
| pull-requests: write | ||
| contents: read | ||
| with: | ||
| bazel-docs-verify-target: "--lockfile_mode=error //:docs" | ||
|
|
||
| docs-build: | ||
| needs: [docs-verify] | ||
| if: github.event_name != 'pull_request' | ||
| uses: eclipse-score/cicd-workflows/.github/workflows/docs.yml@c1c90b1a82a1fab0fc202979dde6686b2162d5a8 # v0.0.0 | ||
| permissions: | ||
| contents: write | ||
| pages: write | ||
| pull-requests: write | ||
| id-token: write | ||
| with: | ||
| bazel-target: "--lockfile_mode=error //:docs -- --github_user=${{ github.repository_owner }} --github_repo=${{ github.event.repository.name }}" | ||
|
AlexanderLanin marked this conversation as resolved.
|
||
| retention-days: 3 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| .. | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| .. _itf_architecture: | ||
|
|
||
| Architecture | ||
| ============ | ||
|
|
||
| This page explains the core design decisions in ITF: the target abstraction | ||
| layer, the capability system, the plugin lifecycle, and how ITF integrates | ||
| bidirectionally with Bazel. | ||
|
|
||
| .. plantuml:: itf_architecture.puml | ||
|
|
||
| Target abstraction layer | ||
| ------------------------ | ||
|
|
||
| The central concept in ITF is the ``Target``. A target represents the device | ||
| or environment under test — a Docker container, a QEMU virtual machine, or | ||
| real hardware. All target types expose the same interface, so test code does | ||
| not need to know which environment it runs on. | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| class Target: | ||
| def execute(self, command): ... | ||
| def upload(self, local_path, remote_path): ... | ||
| def download(self, remote_path, local_path): ... | ||
| def restart(self): ... | ||
| def get_capabilities(self) -> Set[str]: ... | ||
|
|
||
| A test that calls ``target.execute("uname -a")`` runs unchanged against a | ||
| Docker container or a QEMU VM. The target type is determined at build time by | ||
| the ``plugins`` attribute on ``py_itf_test``, and at run time by the CLI | ||
| args (e.g. ``--docker-image``) that configure the chosen plugin. | ||
|
|
||
| Capability system | ||
| ----------------- | ||
|
|
||
| Different target environments support different operations. A plain Docker | ||
| container supports ``exec`` and file transfer but not SSH or SFTP unless an | ||
| SSH server is installed. A QEMU VM provides SSH, SFTP, and network-level | ||
| operations. | ||
|
|
||
| Each ``Target`` subclass declares its capabilities, either by passing them | ||
| to the base constructor or by relying on ``Target.REQUIRED_CAPABILITIES`` | ||
| (``exec``, ``file_transfer``, ``restart``), which is always merged in. | ||
| ``DockerTarget`` uses only the required capabilities, so it passes no | ||
| extras: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| class DockerTarget(Target): | ||
| def __init__(self, container): | ||
| super().__init__() # capabilities come from REQUIRED_CAPABILITIES | ||
| self.container = container | ||
|
|
||
| Tests can be guarded against targets that lack required capabilities using the | ||
| ``@requires_capabilities`` decorator: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from score.itf.plugins.core import requires_capabilities | ||
|
|
||
| @requires_capabilities("ssh", "sftp") | ||
| def test_file_roundtrip(target): | ||
| ... | ||
|
|
||
| If the active target does not provide all listed capabilities, pytest skips the | ||
| test with a clear message. This keeps test suites portable: the same file can | ||
| run against Docker for fast feedback and against a QEMU VM for full-system | ||
| integration, skipping tests that do not apply. | ||
|
|
||
| Tests can also query capabilities at runtime and branch accordingly: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| def test_adaptive(target): | ||
| if target.has_capability("ssh"): | ||
| with target.ssh() as ssh: | ||
| ssh.execute_command("echo hello") | ||
| else: | ||
| exit_code, _ = target.execute("echo hello") | ||
|
|
||
| Plugin lifecycle | ||
| ---------------- | ||
|
|
||
| Each plugin contributes a ``target_init`` pytest fixture. ITF's core plugin | ||
|
clanghans marked this conversation as resolved.
|
||
| calls this fixture to obtain the target instance, then wraps it in the | ||
| ``target`` fixture that test functions receive. | ||
|
|
||
| The lifecycle for a single test is: | ||
|
|
||
| 1. **Setup**: The plugin's ``target_init`` fixture starts the target | ||
| (spins up a container, boots a QEMU VM, connects to hardware). | ||
| 2. **Test execution**: The test function receives the ``target`` fixture | ||
| and exercises the system under test. | ||
| 3. **Teardown**: ``target_init`` tears down the target (stops the | ||
| container, shuts down the VM). | ||
|
|
||
| With ``--keep-target``, steps 1 and 3 run once per session instead of once | ||
| per test function. This is faster but means tests share target state, so it | ||
| should only be used when tests are designed to be order-independent. | ||
|
|
||
| **Plugin loading order is deterministic but should not be relied upon.** | ||
| The core plugin is always registered first. The remaining plugins are | ||
| registered with pytest in the exact order they are listed in | ||
| ``py_itf_test.plugins``. While this order is stable, plugins are designed | ||
| to be independent of each other — no plugin should depend on another | ||
| plugin's initialisation having completed first. | ||
|
|
||
| Why a plugin-based design | ||
| -------------------------- | ||
|
|
||
| Plugin-based design was chosen for three reasons: | ||
|
|
||
| **Separation of concerns.** Target management logic (starting containers, | ||
| booting VMs) is entirely isolated from test logic. A test that calls | ||
| ``target.execute()`` has no dependency on Docker or QEMU APIs. | ||
|
|
||
| **Extensibility without forking.** Custom targets (real hardware, emulators, | ||
| cloud VMs) are added by implementing ``Target`` and ``target_init`` in a new | ||
| plugin. No changes to the ITF core are needed. | ||
|
|
||
| **Bazel-native composition.** Because plugins are declared as Bazel targets | ||
| with ``py_itf_plugin``, they carry their own Python libraries, data files, | ||
| and CLI args. Combining plugins — for example Docker + DLT — is as simple as | ||
| listing both labels in ``py_itf_test.plugins``. Bazel resolves transitive | ||
| dependencies automatically. | ||
|
|
||
| Bidirectional Bazel integration | ||
| --------------------------------- | ||
|
|
||
| ITF integrates with Bazel in both directions: | ||
|
|
||
| **Build-time** (Bazel → ITF): The ``py_itf_test`` symbolic macro creates a | ||
| ``py_test`` binary that bundles the test code and all plugin Python | ||
| libraries. Plugin CLI args (e.g. ``--docker-image``, paths from | ||
| ``$(location ...)``) are resolved at analysis time and baked into a launcher | ||
| script. This means test hermetically carry their full dependency graph, | ||
| including container images or QEMU images referenced via Bazel labels. | ||
|
|
||
| **Run-time** (ITF → Bazel): ITF uses Bazel's runfiles mechanism to locate | ||
| data files at runtime. The ``$(location ...)`` substitution in ``args`` | ||
| produces runfiles-relative paths that work regardless of where Bazel places | ||
| files in the output tree. Test results are reported via JUnit XML to | ||
| ``$XML_OUTPUT_FILE``, integrating with Bazel's native test reporting and | ||
| caching. | ||
|
|
||
| This design means ITF tests participate fully in Bazel's incremental build | ||
| and caching: a test is only re-run if its source, its dependencies, or its | ||
| configuration changes. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| .. | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| .. _itf_concepts: | ||
|
|
||
| Concepts | ||
| ======== | ||
|
|
||
| Architecture, design decisions, and explanatory material for ITF. | ||
|
clanghans marked this conversation as resolved.
|
||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
|
|
||
| architecture | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| @startuml ITF Architecture | ||
| !pragma layout smetana | ||
| skinparam componentStyle rectangle | ||
| skinparam defaultFontName sans-serif | ||
| skinparam linetype ortho | ||
|
|
||
| ' ── Test layer ──────────────────────────────────────────────────────────────── | ||
| package "Test Code" { | ||
| component "test_*.py\n(pytest test function)" as TestFn | ||
| component "@requires_capabilities\n(optional guard)" as RC | ||
| } | ||
|
|
||
| ' ── ITF Core ────────────────────────────────────────────────────────────────── | ||
| package "ITF Core (score.itf.plugins.core)" { | ||
| component "target fixture" as TargetFx | ||
| component "target_init fixture\n(plugin hook)" as TargetInit | ||
| } | ||
|
|
||
| ' ── Target abstraction ──────────────────────────────────────────────────────── | ||
| package "Target Abstraction" { | ||
| component "Target (base class)\n──────────────────\nexecute(cmd)\nupload(src, dst)\ndownload(src, dst)\nrestart()\nhas_capability(cap)\nget_capabilities() : Set[str]" as Target | ||
| } | ||
|
|
||
| ' ── Plugin implementations ──────────────────────────────────────────────────── | ||
| package "Plugins" { | ||
| component "Docker Plugin\n──────────\ncapabilities:\nexec | file_transfer\nrestart" as DockerPlugin | ||
|
|
||
| component "QEMU Plugin\n──────────\ncapabilities:\nssh | sftp | exec\nfile_transfer | restart" as QemuPlugin | ||
|
|
||
| component "DLT Plugin\n──────────\nDltWindow\ndlt_config fixture" as DltPlugin | ||
| } | ||
|
|
||
| ' ── Infrastructure ──────────────────────────────────────────────────────────── | ||
| package "Infrastructure" { | ||
| database "Docker Daemon" as DockerInfra | ||
| database "QEMU VM" as QemuInfra | ||
| } | ||
|
|
||
| ' ── Bazel build layer ───────────────────────────────────────────────────────── | ||
| package "Bazel Build" { | ||
| component "py_itf_test\n(symbolic macro)" as PyItfTest | ||
| component "py_itf_plugin\n(rule)" as PyItfPlugin | ||
| } | ||
|
|
||
| ' ── Relationships ───────────────────────────────────────────────────────────── | ||
| TestFn -down-> TargetFx : receives | ||
| TestFn .right.> RC : guarded by | ||
| TargetFx -down-> TargetInit : delegates to | ||
| TargetInit -down-> Target : yields instance of | ||
| DockerPlugin -up--|> Target : implements | ||
| QemuPlugin -up--|> Target : implements | ||
|
|
||
| DockerPlugin -down-> DockerInfra : manages lifecycle | ||
| QemuPlugin -down-> QemuInfra : manages lifecycle | ||
|
|
||
| TestFn ..> DltPlugin : optional\nDltWindow usage | ||
|
|
||
| PyItfTest -right-> PyItfPlugin : composes plugins | ||
| PyItfPlugin -up-> TargetInit : provides\ntarget_init fixture | ||
|
|
||
| @enduml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # ******************************************************************************* | ||
| # Copyright (c) 2026 Contributors to the Eclipse Foundation | ||
| # | ||
| # See the NOTICE file(s) distributed with this work for additional | ||
| # information regarding copyright ownership. | ||
| # | ||
| # This program and the accompanying materials are made available under the | ||
| # terms of the Apache License Version 2.0 which is available at | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # ******************************************************************************* | ||
|
|
||
| project = "Score ITF" | ||
| project_url = "https://github.com/eclipse-score/itf" | ||
|
|
||
| extensions = [ | ||
| "score_sphinx_bundle", | ||
| ] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.