Skip to content

Commit 86a0fd6

Browse files
committed
πŸ™ chore: enhance CI/CD, versioning, and testing setup
β€’ use importlib.metadata for version and description in Settings β€’ add CI/CD pipeline on main branch for testing and auto-release pypi and docker β€’ add new test for UVX functionality to ensure reliability
1 parent 83f3a8b commit 86a0fd6

20 files changed

+242
-121
lines changed

β€Ž.github/workflows/1_tests.ymlβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
name: Tests
22

33
on:
4-
push:
5-
branches:
6-
- main
74
pull_request:
85
types:
96
- opened
107
- synchronize
8+
workflow_call:
119

1210
permissions: {} # deny all by default
1311

β€Ž.github/workflows/2.1_build-python-package.ymlβ€Ž

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ on:
1010
publish:
1111
description: 'Whether to publish the package (true/false)'
1212
required: false
13-
default: 'false'
14-
type: string
13+
default: false
14+
type: boolean
1515
upload-github-release:
1616
description: 'Whether to upload the built package to a GitHub Release (true/false)'
1717
required: false
18-
default: 'false'
19-
type: string
18+
default: false
19+
type: boolean
2020
outputs:
2121
version:
2222
description: 'Extracted version from pyproject.toml'
@@ -62,15 +62,15 @@ jobs:
6262
run: uv build
6363

6464
- name: Publish package to PyPI (trusted publishing)
65-
if: ${{ inputs.publish == 'true' }}
65+
if: ${{ inputs.publish == true }}
6666
uses: pypa/[email protected]
6767
with:
6868
user: __token__
6969
password: ${{ secrets.PYPI_API_TOKEN }}
7070
verbose: true # Optional, logs more info
7171

7272
- name: Upload Python package to GitHub Release
73-
if: ${{ inputs.upload-github-release == 'true' }}
73+
if: ${{ inputs.upload-github-release == true }}
7474
uses: softprops/action-gh-release@v2
7575
with:
7676
tag_name: v${{ steps.get_version.outputs.version }}

β€Ž.github/workflows/2.2_build-docker-image.ymlβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ on:
2121
push:
2222
description: 'Whether to push the image (true/false)'
2323
required: false
24-
default: 'false'
25-
type: string
24+
default: false
25+
type: boolean
2626
extra-tag:
2727
description: 'An extra tag to apply to the image (e.g., latest)'
2828
required: false
@@ -51,7 +51,7 @@ jobs:
5151
- name: Set up Docker Buildx
5252
uses: docker/setup-buildx-action@v3
5353
- name: Log in to GitHub Container Registry
54-
if: ${{ inputs.push == 'true' }}
54+
if: ${{ inputs.push == true }}
5555
uses: docker/login-action@v3
5656
with:
5757
registry: ghcr.io

β€Ž.github/workflows/2_release.ymlβ€Ž

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
name: Release Python Package and Docker Image
22

33
on:
4+
workflow_call:
5+
inputs:
6+
publish:
7+
description: 'Whether to publish the Python package and Docker image'
8+
required: false
9+
default: false
10+
type: boolean
411
workflow_dispatch:
512
inputs:
613
publish:
7-
description: 'Whether to publish the Python package and Docker image (true/false)'
14+
description: Publish package and Docker image?
815
required: false
16+
type: choice
917
default: 'false'
18+
options:
19+
- 'true'
20+
- 'false'
1021

1122
# This workflow is intended to be run manually for releases.
1223
# It does not depend on CI passing, but it is recommended to only run after CI passes.
@@ -25,18 +36,6 @@ jobs:
2536
run: echo "$GITHUB_CONTEXT"
2637
- id: lower
2738
run: echo "github_repository_lowercase=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT
28-
29-
build-python-package:
30-
needs: params
31-
uses: ./.github/workflows/2.1_build-python-package.yml
32-
permissions:
33-
id-token: write
34-
contents: read
35-
with:
36-
publish: ${{ github.event.inputs.publish }}
37-
upload-github-release: 'false'
38-
secrets: inherit
39-
4039
build-docker-image:
4140
needs: [params, build-python-package]
4241
uses: ./.github/workflows/2.2_build-docker-image.yml
@@ -48,12 +47,21 @@ jobs:
4847
extra-tag: ghcr.io/${{ needs.params.outputs.github-repository-lowercase }}:latest
4948
context: .
5049
dockerfile: Dockerfile
51-
push: ${{ github.event.inputs.publish }}
50+
push: ${{ inputs.publish == 'true' || inputs.publish == true }}
51+
secrets: inherit
52+
build-python-package:
53+
needs: params
54+
uses: ./.github/workflows/2.1_build-python-package.yml
55+
permissions:
56+
id-token: write
57+
contents: read
58+
with:
59+
publish: ${{ inputs.publish == 'true' || inputs.publish == true }}
60+
upload-github-release: false
5261
secrets: inherit
53-
5462
create-github-release:
5563
needs: [params, build-python-package, build-docker-image]
56-
if: ${{ github.event.inputs.publish == 'true' && needs.build-python-package.result == 'success' && needs.build-docker-image.result == 'success' }}
64+
if: ${{ (inputs.publish == 'true' || inputs.publish == true) && needs.build-python-package.result == 'success' && needs.build-docker-image.result == 'success' }}
5765
uses: ./.github/workflows/2.3_create-github-release.yml
5866
permissions:
5967
contents: write
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: CI/CD
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions: {}
9+
10+
jobs:
11+
tests:
12+
name: Run full test suite
13+
uses: ./.github/workflows/1_tests.yml
14+
permissions:
15+
contents: read
16+
actions: write # reusable workflow uploads artifacts
17+
18+
release:
19+
name: Release Python Package and Docker Image
20+
needs: tests
21+
if: success()
22+
uses: ./.github/workflows/2_release.yml
23+
with:
24+
publish: true
25+
secrets: inherit
26+
permissions:
27+
id-token: write
28+
contents: write
29+
packages: write

β€Ž.github/workflows/README.mdβ€Ž

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## πŸ“‚ Workflow Overview
44

55
This repository uses modular, clearly named workflows for CI, integration tests, packaging, Docker, and releases.
6+
A top-level **`0_ci-cd.yaml`** orchestrates the process for pushes to `main`, running **Tests** first and triggering the **Release** workflow only if they pass.
67

78
1. πŸ§ͺ **Tests** β€” lint, types checks, unit, integration and e2e tests.
89
- 🧩 **Unit Tests** β€” Run unit tests
@@ -12,6 +13,7 @@ This repository uses modular, clearly named workflows for CI, integration tests,
1213
- πŸ“¦ **Build & Publish Python Package** β€” Build and (optionally) publish the Python package
1314
- πŸ‹ **Build & Push Docker Image** β€” Build and (optionally) push the Docker image
1415
- πŸ“ **Create GitHub Release Only** β€” Create a GitHub Release from already published artifacts
16+
3. πŸ”„ **CI/CD Orchestration** (`3_ci-cd.yaml`) β€” Runs Tests β†’ Release when pushing to `main`.
1517

1618
## ⚑ Quick Start
1719

@@ -101,6 +103,14 @@ Create a GitHub Release from already published artifacts:
101103
act -W .github/workflows/2.3_create-github-release.yml -P ubuntu-latest=catthehacker/ubuntu:act-latest --rm
102104
```
103105

106+
## 3. πŸ”„ CI/CD Orchestration
107+
108+
Run the combined CI + Release process (push to main simulation):
109+
110+
```sh
111+
act -W .github/workflows/3_ci-cd.yaml -P ubuntu-latest=catthehacker/ubuntu:act-latest --rm
112+
```
113+
104114
## πŸ’‘ Notes
105115

106116
- 🐳 You need Docker running.

β€Žconfig.yamlβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
package_name: mcp-selenium-grid # pyproject.toml
12
project_name: MCP Selenium Grid
23
deployment_mode: docker # one of: docker, kubernetes (DeploymentMode enum values)
34
api_v1_str: /api/v1

β€Žpyproject.tomlβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
[project]
1515
name = "mcp-selenium-grid"
16-
version = "0.1.0.dev5"
16+
version = "0.1.0.dev6"
1717
description = "MCP Server for managing Selenium Grid"
1818
readme = "README.md"
1919
license = { file = "LICENSE" }
@@ -58,6 +58,7 @@ test = [
5858
"pytest-asyncio>=1.0.0", # Parallel test execution
5959
"pytest-sugar>=1.0.0",
6060
"coverage>=7.10.2",
61+
"pytest-timeout>=2.4.0",
6162
]
6263

6364
[build-system]

β€Žsrc/app/common/toml.pyβ€Ž

Lines changed: 0 additions & 55 deletions
This file was deleted.

β€Žsrc/app/core/settings.pyβ€Ž

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
"""Core settings for MCP Server."""
22

3-
from pydantic import Field, SecretStr, field_validator
3+
from importlib.metadata import metadata, version
4+
5+
from pydantic import Field, SecretStr
46

5-
from app.common.toml import load_value_from_toml
67
from app.services.selenium_hub.models.general_settings import SeleniumHubGeneralSettings
78

89

910
class Settings(SeleniumHubGeneralSettings):
1011
"""MCP Server settings."""
1112

12-
# API Settings
13+
# Project Settings
14+
PACKAGE_NAME: str = "mcp-selenium-grid"
1315
PROJECT_NAME: str = "MCP Selenium Grid"
14-
VERSION: str = ""
1516

16-
@field_validator("VERSION", mode="before")
17-
@classmethod
18-
def load_version_from_pyproject(cls, v: str) -> str:
19-
return v or load_value_from_toml(["project", "version"])
17+
@property
18+
def VERSION(self) -> str:
19+
return version(self.PACKAGE_NAME)
2020

21-
API_V1_STR: str = "/api/v1"
21+
@property
22+
def DESCRIPTION(self) -> str:
23+
return metadata(self.PACKAGE_NAME).get("Summary", "").strip()
2224

23-
# API Token
25+
# API Settings
26+
API_V1_STR: str = "/api/v1"
2427
API_TOKEN: SecretStr = SecretStr("CHANGE_ME")
2528

2629
# Security Settings

0 commit comments

Comments
Β (0)