Skip to main content

Publish Allure static reports to private S3 behind CloudFront with history preservation

Project description

pytest-allure-host

CI CodeQL PyPI - Version License: MIT Docs CDK Stack

Publish Allure static reports to private S3 behind CloudFront with history preservation and SPA-friendly routing.

Optional infrastructure (AWS CDK stack to provision the private S3 bucket + CloudFront OAC distribution) lives externally: https://github.com/darrenrabbs/allurehosting-cdk

See docs/architecture.md and .github/copilot-instructions.md for architecture and design constraints.

Documentation

Full documentation (quickstart, AWS setup, IAM least-privilege, CLI usage, changelog) is published at:

https://darrenrabbs.github.io/allurehosting/

The README intentionally stays lean—refer to the site for detailed guidance.

Features

  • Generate Allure static report from allure-results
  • Preserve history by pulling latest/history before generation
  • Upload to S3 under <project>/<branch>/<run_id>/ and update <project>/<branch>/latest/
  • Two-phase latest update: upload to latest_tmp/, swap into latest/, write LATEST_READY marker
  • Optional retention: keep only N newest runs (--max-keep-runs)
  • Correct caching headers: index.html and widgets/no-cache; assets → immutable
  • Optional TTL tagging on objects (--ttl-days) for S3 lifecycle policies
  • Optional summary JSON output for CI
  • Best-effort manifest at runs/index.json with new run metadata
  • Lightweight pointer file latest.json (branch root)
  • Human-friendly HTML index at runs/index.html for navigating past runs
    • Columns: Run ID, raw epoch, UTC Time (human readable), Size (pretty units), P/F/B (passed/failed/broken counts), links to the immutable run and the moving latest
    • Newest run highlighted with a star (★) and soft background

Quick start

# Install the publisher
pip install pytest-allure-host

# Run your test suite and produce allure-results/
pytest --alluredir=allure-results

# Plan (no uploads) – shows what would be published
publish-allure \
  --bucket my-allure-bucket \
  --project myproj \
  --branch main \
  --dry-run --summary-json plan.json

# Real publish (requires AWS creds: env vars, profile, or OIDC)
publish-allure \
  --bucket my-allure-bucket \
  --project myproj \
  --branch main

Notes:

  • --prefix defaults to reports; omit unless you need a different root.
  • --branch defaults to $GIT_BRANCH or main if unset.
  • Add --cloudfront https://reports.example.com to print CDN URLs.
  • Use --check to preflight (AWS / allure binary / inputs) before a real run.
  • Add --context-url https://jira.example.com/browse/PROJ-123 to link a change ticket in the runs index.
  • Use --dry-run + --summary-json in CI for a planning stage artifact.
  • Provide --ttl-days and/or --max-keep-runs for lifecycle & cost controls.

Requirements

  • Python 3.9+
  • AWS credentials with S3 access to the target bucket
  • Allure commandline available on PATH (e.g., via Allure CLI or allure-pytest)

S3 layout and caching

  • Keys:
    • s3://<bucket>/<prefix>/<project>/<branch>/<run_id>/...
    • s3://<bucket>/<prefix>/<project>/<branch>/latest/...
    • s3://<bucket>/<prefix>/<project>/<branch>/runs/index.json (manifest)
    • s3://<bucket>/<prefix>/<project>/<branch>/runs/index.html (HTML index)
    • s3://<bucket>/<prefix>/<project>/<branch>/latest.json (pointer)
  • Two-phase swap writes a LATEST_READY marker file under latest/ when ready.
  • Cache-Control:
    • index.html: no-cache
    • files under widgets/: no-cache
    • everything else: public, max-age=31536000, immutable

CLI usage

Install locally for development:

pip install -e .[dev]

Run the publisher after tests generate allure-results:

publish-allure \
  --bucket your-bucket \
  --prefix reports \
  --project demo \
  --branch main \
  --cloudfront https://reports.example.com \
  --ttl-days 30 \
  --max-keep-runs 10

Flags (CLI):

  • --bucket (required): S3 bucket name
  • --prefix (default: reports): Root prefix
  • --project (required): Project name
  • --branch (default: $GIT_BRANCH or main)
  • --run-id (default: $ALLURE_RUN_ID or YYYYMMDD-HHMMSS)
  • --cloudfront (optional; default: $ALLURE_CLOUDFRONT)
  • --results (default: allure-results): Input directory
  • --report (default: allure-report): Output directory
  • --ttl-days (optional): Add ttl-days=<N> object tag
  • --max-keep-runs (optional): Keep N newest run prefixes, delete older
  • --summary-json <path>: Write machine-readable summary
  • --check: Preflight validation (AWS access, allure, inputs)
  • --dry-run: Print planned prefixes and sample headers, no upload
  • --skip-preflight: Skip automatic preflight before publish (not recommended)
  • --allow-duplicate-prefix-project: Allow prefix == project (guard is on by default)
  • --s3-endpoint: Custom S3 endpoint (e.g. http://localhost:4566 for LocalStack)

Environment fallbacks:

  • ALLURE_BUCKET--bucket
  • ALLURE_PREFIX--prefix
  • ALLURE_PROJECT--project
  • GIT_BRANCH--branch default
  • ALLURE_RUN_ID--run-id default
  • ALLURE_CLOUDFRONT--cloudfront default
  • ALLURE_AWS_REGION → preferred region used in preflight comparison
  • ALLURE_CLOUDFRONT_DISTRIBUTION_ID → explicit distribution id for preflight
  • ALLURE_S3_ENDPOINT--s3-endpoint default (LocalStack / custom S3)

Pytest plugin usage

Run tests and publish during terminal summary:

pytest \
  --allure-bucket your-bucket \
  --allure-prefix reports \
  --allure-project demo \
  --allure-branch main \
  --allure-cloudfront https://reports.example.com \
  --allure-ttl-days 30 \
  --allure-max-keep-runs 10

Flags (pytest):

  • --allure-bucket (required)
  • --allure-prefix (default: reports)
  • --allure-project (required)
  • --allure-branch (default: $GIT_BRANCH or main)
  • --allure-run-id (default: $ALLURE_RUN_ID or YYYYMMDD-HHMMSS)
  • --allure-cloudfront (optional; default: $ALLURE_CLOUDFRONT)
  • --allure-ttl-days (optional)
  • --allure-max-keep-runs (optional)
  • --allure-summary-json <path> (optional)
  • --allure-check / --allure-dry-run (optional)

Preflight and dry-run

Preflight runs automatically before a real publish. You can also run it explicitly with --check. Use --skip-preflight only if you know what you’re doing.

What preflight validates (read‑only):

  • Local inputs: allure-results exists and is non-empty; Allure CLI is available on PATH.
  • S3 bucket:
    • HeadBucket and a small ListObjectsV2 to confirm existence and access.
    • Public Access Block: all four flags must be true.
    • Bucket policy status: IsPublic must be false.
    • Region detection and comparison against ALLURE_AWS_REGION/aws_region if provided.
  • CloudFront distribution:
    • When ALLURE_CLOUDFRONT_DISTRIBUTION_ID/cloudfront_distribution_id is set, it is used directly.
    • Otherwise, the distribution is discovered from --cloudfront domain/aliases.
    • Status must be Deployed, and an Origin Access Control (OAC) must be attached to at least one origin (legacy OAI is not sufficient).

On success, a concise line is printed in addition to the machine-readable dict:

[preflight] OK — bucket=my-bucket, region=eu-west-1, distribution=E123ABC456

--dry-run/--allure-dry-run prints planned S3 keys and cache headers; no uploads occur.

Guardrails:

  • The CLI fails fast if prefix == project to avoid redundant S3 paths. If this is intentional, pass --allow-duplicate-prefix-project.

Config keys (YAML or env) relevant to preflight:

# application.yml / allure-host.yml
bucket: my-bucket
prefix: reports
project: demo
branch: main
cloudfront: https://reports.example.com
aws_region: us-east-1 # used for region comparison
cloudfront_distribution_id: E123ABC456 # preferred for deterministic preflight

Environment equivalents:

ALLURE_BUCKET, ALLURE_PREFIX, ALLURE_PROJECT, ALLURE_BRANCH,
ALLURE_CLOUDFRONT, ALLURE_AWS_REGION, ALLURE_CLOUDFRONT_DISTRIBUTION_ID

Configuration resolution & debug

How values are resolved at runtime (highest wins):

  • CLI flags
  • YAML (allure-host.yml / application.yml)
  • Environment variables (including .infra_env exports)
  • Built-in defaults

Notes:

  • .infra_env fallbacks are supported for quick bootstrap: BUCKET, AWS_REGION, DISTRIBUTION_ID, and CF_DOMAIN map to their canonical keys.

  • CloudFront base is normalized. If you pass reports.example.com we treat it as https://reports.example.com; any trailing / is stripped.

  • To see where each key came from, enable source logging:

    ALLURE_HOST_DEBUG=1 publish-allure --check
    # Example excerpt
    #  Loaded config:
    #    bucket = my-bucket  (env)
    #    aws_region = eu-west-1  (yaml)
    #    cloudfront_distribution_id = E123ABC456  (env)
    #    cloudfront_domain = https://d123abcd.cloudfront.net  (env)
    #    project = payments  (yaml)
    #    branch = main  (cli)
    

Preflight gate: both publish-allure --check and automatic preflight before a real publish compute a single preflight_ok boolean from the critical checks (allure CLI, results present, S3 reachability and privacy, CloudFront distribution deployed with OAC). The CLI prefers this gate to decide pass/fail and will also list failing gates when blocked.

Outputs

  • S3 prefixes: run and latest
  • Optional CDN URLs (if --cloudfront provided)
  • runs/index.json manifest updated with new run entry
  • runs/index.html HTML table of recent runs (newest first) with columns: Run ID, Epoch, UTC Time, Size, P/F/B, Run, Latest (newest row highlighted with ★)
  • latest.json pointer to current run (simple machine-readable metadata)
  • Optional --summary-json with sizes, file counts, and destination URLs
  • latest/LATEST_READY marker indicates the swap is complete

Security

See SECURITY.md for how to report vulnerabilities. Never open a public issue containing sensitive details.

Badges / Status

  • CI: multi-version test matrix + lint/security
  • CodeQL: static code analysis

Contributing

See CONTRIBUTING.md and follow the pre-commit hooks (pre-commit install).

Release

Tagged versions (vX.Y.Z) are published to PyPI automatically via GitHub OIDC.

CI examples

GitHub Actions (CLI):

jobs:
  tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.11" }
      - run: pip install .[dev]
      - run: pytest -q
      - name: Publish Allure
        env:
          AWS_REGION: us-east-1
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          GIT_BRANCH: ${{ github.ref_name }}
        run: >-
          publish-allure --bucket $BUCKET --prefix reports --project demo
          --branch "$GIT_BRANCH" --cloudfront https://reports.example.com
          --ttl-days 30 --max-keep-runs 10

Pytest-driven (plugin):

- run: pytest -q \
    --allure-bucket $BUCKET \
    --allure-prefix reports \
    --allure-project demo \
    --allure-branch "$GIT_BRANCH" \
    --allure-cloudfront https://reports.example.com \
    --allure-ttl-days 30 \
    --allure-max-keep-runs 10

Minimal publish-only workflow

Create .github/workflows/allure-publish.yml for a lightweight pipeline that runs tests, generates the report, and publishes it (using secrets for the bucket and AWS credentials):

name: allure-publish
on: [push, pull_request]
jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install deps (minimal)
        run: pip install pytest pytest-allure-host allure-pytest
      - name: Run tests
        run: pytest --alluredir=allure-results -q
      - name: Publish Allure report (dry-run on PRs)
        env:
          AWS_REGION: us-east-1
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          ALLURE_BUCKET: ${{ secrets.ALLURE_BUCKET }}
        run: |
          EXTRA=""
          if [ "${{ github.event_name }}" = "pull_request" ]; then EXTRA="--dry-run"; fi
          publish-allure \
            --bucket "$ALLURE_BUCKET" \
            --project myproj \
            --branch "${{ github.ref_name }}" \
            --summary-json summary.json $EXTRA
      - name: Upload publish summary (always)
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: allure-summary
          path: summary.json

Notes:

  • Add --cloudfront https://reports.example.com if you have a CDN domain.
  • Add --context-url ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }} inside PRs to link the run to its PR.
  • Use --max-keep-runs / --ttl-days to manage storage costs.
  • For LocalStack-based tests, set --s3-endpoint and export ALLURE_S3_ENDPOINT in env:.

Troubleshooting

  • Missing Allure binary: ensure the Allure CLI is installed and on PATH.
  • Access denied: verify AWS credentials and bucket IAM for Put/Get/List/Delete.
  • SPA routing 403/404: configure CloudFront error mapping to /index.html.
  • See ISSUES.md for known pitfalls and fixes (CDN staleness, venv alignment for seeding/invalidation, auto-build helpers).

Style tweaks (dashboard)

You can adjust dashboard typography and KPI sizing via CSS variables without editing the stylesheet. Add these anywhere global (e.g., a small <style> tag or a site-wide CSS file):

/* Example: make KPI label/value bigger and cards taller in v2 */
body {
  --kpi-title-size: 13px; /* KPI label, e.g., "FAILURES" */
  --kpi-value-size: 20px; /* big number */
  --kpi-delta-size: 13px; /* ▲ ▼ delta text */
  --kpi-card-height: 180px; /* v2 KPI card height */
}

Available variables (defaults shown):

  • --kpi-title-size: 12px
  • --kpi-value-size: 18px
  • --kpi-delta-size: 12px
  • --kpi-card-height: 160px (v2)
  • --kpi-card-min-height-v1: 64px (v1)

The stylesheet web/static/css/runs-polish.css is now organized with clear section headers for quick navigation:

  • Section: KPI cards (v1)
  • Section: V2 overrides (top-level, high specificity)
  • Section: V2 failure summary sidebar
  • Section: V2 general card chrome and text sizes

Development

  • Install with Poetry: poetry install
  • Run tests: poetry run pytest -q
  • Lint (security quick): poetry run bandit -r pytest_allure_host
  • Unified lint helper (mirrors CI):
    scripts/lint.sh           # check mode (ruff lint+format check, bandit, pip-audit)
    scripts/lint.sh --fix     # apply ruff fixes + format
    scripts/lint.sh pre-commit  # also run pre-commit hooks on all files
    

Quick local trial (macOS)

This section walks you through a minimal end-to-end run locally.

  1. Prereqs
  • AWS credentials configured (via AWS_PROFILE or access keys); set AWS_REGION.
  • Allure CLI installed on PATH:
    brew install allure
    
  • Python deps installed:
    poetry install
    # or
    pip install -e .[dev]
    
  1. Generate Allure results
  • Create a tiny test (optional example):
    mkdir -p tests
    cat > tests/test_sample.py <<'PY'
    def test_ok():
        assert True
    PY
    
  • Run pytest to emit results:
    poetry run pytest --alluredir=allure-results
    
  1. Preflight and dry-run
poetry run publish-allure \
  --bucket <bucket> \
  --prefix reports \
  --project demo \
  --branch $(git rev-parse --abbrev-ref HEAD) \
  --cloudfront https://<cloudfront_domain> \
  --check \
  --dry-run
  1. Publish
poetry run publish-allure \
  --bucket <bucket> \
  --prefix reports \
  --project demo \
  --branch $(git rev-parse --abbrev-ref HEAD) \
  --cloudfront https://<cloudfront_domain> \
  --ttl-days 30 \
  --max-keep-runs 5
  1. Verify
  • S3: reports/demo/<branch>/<run_id>/... and reports/demo/<branch>/latest/ with LATEST_READY.
  • CDN: open printed run_url / latest_url.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_allure_host-2.1.8.tar.gz (116.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_allure_host-2.1.8-py3-none-any.whl (117.2 kB view details)

Uploaded Python 3

File details

Details for the file pytest_allure_host-2.1.8.tar.gz.

File metadata

  • Download URL: pytest_allure_host-2.1.8.tar.gz
  • Upload date:
  • Size: 116.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pytest_allure_host-2.1.8.tar.gz
Algorithm Hash digest
SHA256 97acf898cf3b75dc3a4a297e4be6f8f7c7f787ba5be2a9f14120d218570506e5
MD5 03711eae0b5b27a255c0939b38ffcdd7
BLAKE2b-256 2d14c415bc11fa86045143f2d51020c5c66feb939e44f91a406e1c7d2af04dca

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_allure_host-2.1.8.tar.gz:

Publisher: release.yml on darrenrabbs/allurehosting

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_allure_host-2.1.8-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_allure_host-2.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 508e2fdd6ea1f4b3b257a529b186a0cad2dbd88a15d0503ff0fcbf6204a0b12c
MD5 14eaee86bcdf534f64820854c5c04112
BLAKE2b-256 0cea75ad2d3e979729c5ba030658fb8297b1753134fb65ac2c98e07f6ef8dd97

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_allure_host-2.1.8-py3-none-any.whl:

Publisher: release.yml on darrenrabbs/allurehosting

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page