Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 90 additions & 61 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,112 +1,141 @@
name: CI
# ===============================================================
# 🧪 Tests & Coverage + 📦 Package Build
# ===============================================================
#
# This workflow:
# - Runs pytest with 85% coverage threshold (test)
# - Uploads coverage.xml as artifact (test)
# - Builds wheel/sdist and validates with twine (package)
#
# Lint, type-check, and pre-commit live in separate workflows
# (lint.yml, pre-commit.yml) so they appear as independent
# checks on PRs.
#
# Triggers on push to main and PRs. Skips draft PRs.
# Cancels stale runs on the same branch.
#
# References
# ──────────
# - Poetry: https://python-poetry.org/docs/
# - Pytest: https://docs.pytest.org/
# - Twine: https://twine.readthedocs.io/
#
# Author: Manav Gupta <manavg@gmail.com>
# ===============================================================

name: Tests & Package

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, ready_for_review]
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# -----------------------------------------------------------------
# Minimal permissions — principle of least privilege
# -----------------------------------------------------------------
permissions:
contents: read

# -----------------------------------------------------------------
# Shared environment
# -----------------------------------------------------------------
env:
PYTHONUNBUFFERED: "1"
PIP_DISABLE_PIP_VERSION_CHECK: "1"

jobs:
lint:
name: Lint

# =========================================================================
# 🧪 Tests & Coverage
# =========================================================================
test:
name: Test (py${{ matrix.python }})
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 10
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-python@v5
with:
python-version: "3.12"
strategy:
fail-fast: false
matrix:
python: ["3.12"]

- name: Install Poetry
run: pipx install poetry

- name: Install dependencies
run: poetry install --no-interaction

- name: Ruff check
run: poetry run ruff check .

- name: Black check
run: poetry run black --check .

typecheck:
name: Type Check
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
steps:
- uses: actions/checkout@v4
# ─────────── Setup ───────────
- name: ⬇️ Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-python@v5
- name: 🐍 Setup Python ${{ matrix.python }}
uses: actions/setup-python@v5
with:
python-version: "3.12"
python-version: ${{ matrix.python }}

- name: Install Poetry
- name: 📦 Install Poetry
run: pipx install poetry

- name: Install dependencies
run: poetry install --no-interaction

- name: Mypy
run: poetry run mypy faststack_core/ cli/

test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-python@v5
- name: 💾 Cache Poetry dependencies
uses: actions/cache@v4
with:
python-version: "3.12"
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
restore-keys: ${{ runner.os }}-poetry-

- name: Install Poetry
run: pipx install poetry

- name: Install dependencies
- name: 📦 Install dependencies
run: poetry install --no-interaction

- name: Run tests
run: poetry run pytest -v --tb=short || test $? -eq 5
# ─────────── Test ───────────
- name: 🧪 Run tests with coverage
run: |
poetry run pytest \
--cov \
--cov-report=term \
--cov-report=xml \
--cov-fail-under=85 \
-v --tb=short

- name: 📊 Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-py${{ matrix.python }}
path: coverage.xml

# =========================================================================
# 📦 Package Build
# =========================================================================
package:
name: Package Build
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event_name != 'pull_request' || !github.event.pull_request.draft

steps:
- uses: actions/checkout@v4
# ─────────── Setup ───────────
- name: ⬇️ Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-python@v5
- name: 🐍 Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Poetry
- name: 📦 Install Poetry
run: pipx install poetry

- name: Build package
# ─────────── Build & Validate ───────────
- name: 🔨 Build distributions
run: poetry build

- name: Validate package
- name: Validate package metadata (twine)
run: |
pip install twine
twine check dist/*
46 changes: 42 additions & 4 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
# ===============================================================
# 🔍 Dependency Review — Vulnerabilities & Licenses
# ===============================================================
#
# This workflow:
# - Diffs dependency changes introduced by PRs to `main`
# - **Fails** when a change introduces either:
# ↳ A vulnerability of severity >= MODERATE
# ↳ A dependency under a strong-copyleft license incompatible
# with this project's MIT license (see deny-list below)
#
# Only runs when dependency files change (pyproject.toml, poetry.lock).
# Skips draft PRs.
#
# References
# ──────────
# - Marketplace: https://github.com/marketplace/actions/dependency-review
# - Source code: https://github.com/github/dependency-review-action (MIT)
#
# Author: Manav Gupta <manavg@gmail.com>
# ===============================================================

name: Dependency Review

on:
Expand All @@ -6,24 +28,40 @@ on:
paths:
- "pyproject.toml"
- "poetry.lock"
- ".github/workflows/dependency-review.yml"

# -----------------------------------------------------------------
# Minimal permissions — principle of least privilege
# -----------------------------------------------------------------
permissions:
contents: read
pull-requests: write
contents: read # for actions/checkout
pull-requests: write # post PR comment on failure

jobs:
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
timeout-minutes: 5
if: "!github.event.pull_request.draft"

steps:
- uses: actions/checkout@v4
# ─────────── Checkout ───────────
- name: ⬇️ Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Dependency Review
# ─────────── Scan ───────────
- name: 🔍 Dependency & License gate
uses: actions/dependency-review-action@v4
with:
# ───────── Vulnerability policy ─────────
fail-on-severity: moderate

# ───────── License policy ─────────
# Deny strong-copyleft licenses incompatible with MIT.
# LGPL/MPL are weak copyleft and allowed.
deny-licenses: GPL-3.0, AGPL-3.0, SSPL-1.0

# ───────── UX ─────────
comment-summary-in-pr: on-failure
Loading
Loading