-
Notifications
You must be signed in to change notification settings - Fork 2
Add integration-smoke workflow. #72
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
Merged
wpak-ai
merged 7 commits into
cppalliance:develop
from
whisper67265:feature/integration-smoke
May 27, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
45a72b8
Add integration-smoke test flow
whisper67265 0457f9a
fix CI check-manifest fail
whisper67265 f76667d
fix integration workflow fail
whisper67265 28e961b
fix token generation fail
whisper67265 fc38722
fix django load fail
whisper67265 645af4c
fix smoke tests fail
whisper67265 99af7ff
fix coderabbitai review
whisper67265 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| name: Integration smoke | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main, develop] | ||
| pull_request: | ||
| branches: [main, develop] | ||
|
|
||
| jobs: | ||
| integration-smoke: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| steps: | ||
| # actions/checkout v6.0.2 | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| # actions/setup-python v6.2.0 | ||
| - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 | ||
| with: | ||
| python-version: '3.12' | ||
|
|
||
| - name: Run integration smoke tests | ||
| run: bash scripts/integration-smoke.sh | ||
|
|
||
| - name: Upload logs on failure | ||
| if: failure() | ||
| # actions/upload-artifact v4.6.2 | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | ||
| with: | ||
| name: integration-smoke-logs | ||
| path: /tmp/compose-logs.txt |
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,33 @@ | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| # Overlay image: stock Weblate + cppa-weblate-plugin installed into /app/venv. | ||
| # CI builds with repo root as context (installs checked-out branch). | ||
| # CD builds on the deploy server where the target branch is already checked out. | ||
|
|
||
| FROM weblate/weblate:latest | ||
|
|
||
| # Base image ends with USER 1000; installing into /app/venv requires root. | ||
| USER root | ||
|
|
||
| ARG PLUGIN_GIT_URL=https://github.com/cppalliance/cppa-weblate-plugin.git | ||
| ARG PLUGIN_GIT_REF= | ||
|
|
||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | ||
|
|
||
| COPY src/boost_weblate/settings_override.py /app/data/settings-override.py | ||
|
|
||
| COPY . /tmp/plugin-src/ | ||
| RUN set -eux; \ | ||
| if [ ! -f /tmp/plugin-src/pyproject.toml ]; then \ | ||
| if [ -z "${PLUGIN_GIT_REF}" ]; then \ | ||
| echo "ERROR: No pyproject.toml in build context and PLUGIN_GIT_REF is unset"; exit 1; \ | ||
| fi; \ | ||
| rm -rf /tmp/plugin-src; \ | ||
| git clone --depth 1 --branch "${PLUGIN_GIT_REF}" "${PLUGIN_GIT_URL}" /tmp/plugin-src; \ | ||
| fi; \ | ||
| uv pip install --python /app/venv/bin/python /tmp/plugin-src; \ | ||
| rm -rf /tmp/plugin-src | ||
|
|
||
| USER 1000 | ||
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,14 @@ | ||
| # docker/ | ||
|
|
||
| Shared Docker assets for CI and CD. | ||
|
|
||
| - **Dockerfile.weblate-plugin** — Overlay on `weblate/weblate:latest`; installs the plugin via `uv pip install` and copies `settings-override.py`. | ||
| - **docker-compose.yml** — PostgreSQL + Redis + Weblate stack. Override defaults via `.env` or environment variables. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```bash | ||
| # From repo root: | ||
| docker compose -f docker/docker-compose.yml build | ||
| docker compose -f docker/docker-compose.yml up -d | ||
| ``` |
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,60 @@ | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| # Shared Docker Compose stack for integration tests and CD deployments. | ||
| # CI: docker compose -f docker/docker-compose.yml build && up | ||
| # CD: same file, overridden via .env on the deploy server. | ||
|
|
||
| services: | ||
| postgresql: | ||
| image: postgres:16-alpine | ||
| environment: | ||
| POSTGRES_USER: weblate | ||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-weblate} | ||
| POSTGRES_DB: weblate | ||
|
whisper67265 marked this conversation as resolved.
|
||
| healthcheck: | ||
| test: [CMD, pg_isready, -U, weblate] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 10 | ||
| tmpfs: | ||
| - /var/lib/postgresql/data | ||
|
|
||
| redis: | ||
| image: redis:7-alpine | ||
| healthcheck: | ||
| test: [CMD, redis-cli, ping] | ||
| interval: 5s | ||
| timeout: 3s | ||
| retries: 10 | ||
|
|
||
| weblate: | ||
| build: | ||
| context: .. | ||
| dockerfile: docker/Dockerfile.weblate-plugin | ||
| ports: | ||
| - ${WEBLATE_PORT:-8080}:8080 | ||
| depends_on: | ||
| postgresql: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
| environment: | ||
| WEBLATE_SITE_DOMAIN: ${WEBLATE_SITE_DOMAIN:-localhost:8080} | ||
| WEBLATE_ADMIN_PASSWORD: ${WEBLATE_ADMIN_PASSWORD:-admin} | ||
| WEBLATE_DEBUG: ${WEBLATE_DEBUG:-1} | ||
| POSTGRES_HOST: postgresql | ||
| POSTGRES_PORT: '5432' | ||
| POSTGRES_USER: weblate | ||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-weblate} | ||
| POSTGRES_DATABASE: weblate | ||
| REDIS_HOST: redis | ||
| REDIS_PORT: '6379' | ||
| CELERY_SINGLE_PROCESS: '1' | ||
| healthcheck: | ||
| test: [CMD, curl, -f, http://localhost:8080/healthz/] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 12 | ||
| start_period: 60s | ||
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,20 @@ | ||
| # scripts/ | ||
|
|
||
| Reusable shell scripts for CI and CD. | ||
|
|
||
| - **lib/compose.sh** — Sets `COMPOSE_FILE`, `COMPOSE_PROJECT_NAME`, exports `compose()` wrapper. | ||
| - **lib/weblate-stack.sh** — Stack lifecycle functions: `stack_build`, `stack_up`, `stack_wait_healthy`, `stack_create_token`, `stack_logs`, `stack_down`. | ||
| - **integration-smoke.sh** — CI entrypoint for P0 smoke tests (build, start, health-check, test, teardown). | ||
|
|
||
| ## Usage | ||
|
|
||
| ```bash | ||
| # Run smoke tests locally: | ||
| bash scripts/integration-smoke.sh | ||
|
|
||
| # Source the library for custom workflows: | ||
| source scripts/lib/weblate-stack.sh | ||
| stack_build | ||
| stack_up | ||
| stack_wait_healthy 120 | ||
| ``` |
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,45 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| # Integration smoke test entrypoint. | ||
| # Builds the stack, waits for health, creates a token, runs smoke tests. | ||
| # On exit (success or failure): collects logs and tears down the stack. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| # shellcheck source=lib/weblate-stack.sh | ||
| source "${SCRIPT_DIR}/lib/weblate-stack.sh" | ||
|
|
||
| cleanup() { | ||
| local exit_code=$? | ||
| set +e | ||
| echo "--- Collecting logs ---" | ||
| stack_logs /tmp/compose-logs.txt | ||
| echo "--- Tearing down stack ---" | ||
| stack_down | ||
| exit "$exit_code" | ||
|
whisper67265 marked this conversation as resolved.
|
||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| echo "=== Building stack ===" | ||
| stack_build | ||
|
|
||
| echo "=== Starting stack ===" | ||
| stack_up | ||
|
|
||
| echo "=== Waiting for Weblate ===" | ||
| stack_wait_healthy "${HEALTH_TIMEOUT:-120}" | ||
|
|
||
| echo "=== Creating API token ===" | ||
| WEBLATE_API_TOKEN="$(stack_create_token admin)" | ||
| export WEBLATE_API_TOKEN | ||
| export WEBLATE_LIVE_BASE_URL="${WEBLATE_LIVE_BASE_URL:-http://localhost:${WEBLATE_PORT:-8080}}" | ||
| export WEBLATE_COMPOSE_FILE="${COMPOSE_FILE}" | ||
| export WEBLATE_COMPOSE_PROJECT="${COMPOSE_PROJECT_NAME}" | ||
|
|
||
| echo "=== Running smoke tests ===" | ||
| pip install --quiet pytest | ||
| # Do not load tests/conftest.py (Django host setup); integration tests only need pytest + stdlib. | ||
| python -m pytest --confcutdir=tests/integration --override-ini addopts= tests/integration/test_smoke.py -v | ||
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,21 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| # Shared compose wrapper sourced by other scripts. | ||
| # Sets REPO_ROOT, COMPOSE_FILE, COMPOSE_PROJECT_NAME and exports compose(). | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" | ||
| export REPO_ROOT | ||
|
|
||
| COMPOSE_FILE="${COMPOSE_FILE:-${REPO_ROOT}/docker/docker-compose.yml}" | ||
| export COMPOSE_FILE | ||
|
|
||
| COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-cppa-weblate-plugin}" | ||
| export COMPOSE_PROJECT_NAME | ||
|
|
||
| compose() { | ||
| docker compose -f "$COMPOSE_FILE" -p "$COMPOSE_PROJECT_NAME" "$@" | ||
| } |
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,74 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| # Reusable functions for managing the Weblate Docker Compose stack. | ||
| # Source this file from CI/CD scripts. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| SCRIPT_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| # shellcheck source=compose.sh | ||
| source "${SCRIPT_LIB_DIR}/compose.sh" | ||
|
|
||
| stack_build() { | ||
| compose build "$@" | ||
| } | ||
|
|
||
| stack_up() { | ||
| compose up -d "$@" | ||
| } | ||
|
|
||
| stack_wait_healthy() { | ||
| local timeout="${1:-120}" | ||
| local port="${WEBLATE_PORT:-8080}" | ||
| local url="http://localhost:${port}/healthz/" | ||
| local interval=5 | ||
| local elapsed=0 | ||
|
|
||
| echo "Waiting for Weblate at ${url} (timeout: ${timeout}s)..." | ||
| while [ "$elapsed" -lt "$timeout" ]; do | ||
| if curl -sf "$url" > /dev/null 2>&1; then | ||
| echo "Weblate is healthy (after ${elapsed}s)." | ||
| return 0 | ||
| fi | ||
| sleep "$interval" | ||
| elapsed=$((elapsed + interval)) | ||
| done | ||
|
|
||
| echo "ERROR: Weblate did not become healthy in ${timeout}s." | ||
| echo "--- weblate container logs ---" | ||
| compose logs weblate | tail -80 | ||
| return 1 | ||
| } | ||
|
|
||
| stack_create_token() { | ||
| local user="${1:-admin}" | ||
| # Use python -c (not `weblate shell`) so stdout is only the key | ||
| compose exec -T -e "WEBLATE_CI_USERNAME=${user}" weblate \ | ||
| /app/venv/bin/python -c \ | ||
| 'import os | ||
| os.environ.setdefault("DJANGO_SETTINGS_MODULE", "weblate.settings_docker") | ||
| import django | ||
| django.setup() | ||
| from weblate.auth.models import User | ||
| from rest_framework.authtoken.models import Token | ||
| from weblate.utils.token import get_token | ||
| u = User.objects.get(username=os.environ["WEBLATE_CI_USERNAME"]) | ||
| Token.objects.filter(user=u).delete() | ||
| t = Token.objects.create(user=u, key=get_token("wlp" if u.is_bot else "wlu")) | ||
| print(t.key)' | ||
| } | ||
|
|
||
| stack_logs() { | ||
| local file="${1:-}" | ||
| if [ -n "$file" ]; then | ||
| compose logs > "$file" 2>&1 || true | ||
| else | ||
| compose logs | ||
| fi | ||
| } | ||
|
|
||
| stack_down() { | ||
| compose down -v --remove-orphans 2>/dev/null || true | ||
| } |
Empty file.
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,56 @@ | ||
| # SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com> | ||
| # | ||
| # SPDX-License-Identifier: BSL-1.0 | ||
|
|
||
| """Shared fixtures for integration tests.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import os | ||
| from collections.abc import Callable | ||
| from typing import Any | ||
|
|
||
| import pytest | ||
|
|
||
| from tests.integration.lib.docker_exec import ( | ||
| docker_exec_python, | ||
| docker_exec_python_json, | ||
| ) | ||
| from tests.integration.lib.http import base_url as _base_url | ||
| from tests.integration.lib.http import http_get | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def api_token() -> str: | ||
| token = os.environ.get("WEBLATE_API_TOKEN") | ||
| if not token: | ||
| pytest.skip("WEBLATE_API_TOKEN not set") | ||
| return token | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def live_base_url() -> str: | ||
| return _base_url() | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def authed_get(api_token: str) -> Callable[..., tuple[int, Any]]: # noqa: E501 | ||
| """GET helper pre-bound with the API token.""" | ||
| token = api_token | ||
|
|
||
| def _get(path: str, **kwargs: Any) -> tuple[int, Any]: | ||
| return http_get(path, token=token, **kwargs) | ||
|
|
||
| return _get | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def exec_python() -> Callable[[str], str]: | ||
| """Execute a Python snippet inside the Weblate container.""" | ||
| return docker_exec_python | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def exec_python_json() -> Callable[[str], object]: | ||
| """Execute a Python snippet inside the container and parse JSON output.""" | ||
| return docker_exec_python_json |
Empty file.
Oops, something went wrong.
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.