Cybersecurity-Projects/TEMPLATES/justfile.example

385 lines
11 KiB
Plaintext

# ©AngelaMos | 2026
# justfile.example
#
# Annotated justfile template for Cybersecurity-Projects.
# Copy into your project root, rename to `justfile`, and replace
# every <PLACEHOLDER> with your actual values. Delete sections
# that don't apply to your project's stack.
#
# Docs: https://just.systems/man/en/
# Cheat: https://cheatography.com/linux-china/cheat-sheets/justfile/
#
# Install just:
# cargo install just (from source)
# brew install just (macOS)
# apt install just (Debian/Ubuntu 24.04+)
# pipx install rust-just (via pipx)
#
# Usage:
# just list all available recipes
# just <recipe> run a recipe
# just -n <recipe> dry-run (print commands without executing)
# ── Settings ──────────────────────────────────────────────────────────────────
# These apply globally to every recipe in the file.
# Load .env file into environment for all recipes.
set dotenv-load
# Export all `just` variables as environment variables to child processes.
set export
# Use bash in strict mode (-u = error on unset vars, -c = command string).
# This gives consistent behavior across macOS/Linux regardless of login shell.
set shell := ["bash", "-uc"]
# Windows equivalent (only takes effect on Windows, ignored elsewhere).
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
# ── Variables ─────────────────────────────────────────────────────────────────
# Variables defined here are available in all recipes via {{name}}.
# Backtick expressions run shell commands at parse time.
project := file_name(justfile_directory())
version := `git describe --tags --always 2>/dev/null || echo "dev"`
# Project-specific paths — change these to match your layout.
# Python-only project: src_dir := "src"
# Fullstack project: src_dir := "backend/src"
src_dir := "<src>"
test_dir := "<tests>"
package := "<package-name>"
# ── Default ───────────────────────────────────────────────────────────────────
# The first recipe is the default (runs when you type `just` with no args).
# --unsorted preserves the order defined in this file instead of alphabetizing.
default:
@just --list --unsorted
# =============================================================================
# Linting and Formatting
# =============================================================================
# Ruff handles both linting and formatting for Python.
# `*ARGS` is a variadic parameter — any extra flags you pass get forwarded.
# Example: just ruff --fix
[group('lint')]
ruff *ARGS:
ruff check {{src_dir}}/ {{test_dir}}/ {{ARGS}}
[group('lint')]
ruff-fix:
ruff check {{src_dir}}/ {{test_dir}}/ --fix
ruff format {{src_dir}}/ {{test_dir}}/
[group('lint')]
ruff-format:
ruff format {{src_dir}}/ {{test_dir}}/
[group('lint')]
pylint *ARGS:
pylint {{src_dir}}/{{package}} {{ARGS}}
# Dependency recipes — `lint` runs `ruff` then `pylint` in order.
[group('lint')]
lint: ruff pylint
# =============================================================================
# Frontend Linting (delete this section for Python-only projects)
# =============================================================================
# Biome is an all-in-one linter/formatter for JS/TS (replaces ESLint+Prettier).
# Alternatives: eslint + prettier (shown commented below)
[group('frontend')]
biome *ARGS:
cd frontend && pnpm biome check . {{ARGS}}
[group('frontend')]
biome-fix:
cd frontend && pnpm biome check --write .
[group('frontend')]
stylelint *ARGS:
cd frontend && pnpm stylelint '**/*.scss' {{ARGS}}
[group('frontend')]
stylelint-fix:
cd frontend && pnpm stylelint '**/*.scss' --fix
[group('frontend')]
tsc *ARGS:
cd frontend && pnpm tsc --noEmit {{ARGS}}
# Alternative: ESLint + Prettier (uncomment if not using Biome)
# [group('frontend')]
# eslint *ARGS:
# cd frontend && pnpm eslint . {{ARGS}}
#
# [group('frontend')]
# eslint-fix:
# cd frontend && pnpm eslint . --fix
#
# [group('frontend')]
# prettier *ARGS:
# cd frontend && pnpm prettier --check "src/**/*.{ts,tsx,css}" {{ARGS}}
#
# [group('frontend')]
# prettier-fix:
# cd frontend && pnpm prettier --write "src/**/*.{ts,tsx,css}"
# =============================================================================
# Type Checking
# =============================================================================
[group('types')]
mypy *ARGS:
mypy {{src_dir}}/ {{ARGS}}
# ty is Astral's experimental type checker (fast, Rust-based).
# Uncomment if your project uses it.
# [group('types')]
# ty *ARGS:
# ty check {{ARGS}}
[group('types')]
typecheck: mypy
# =============================================================================
# Testing
# =============================================================================
[group('test')]
pytest *ARGS:
pytest {{test_dir}}/ {{ARGS}}
[group('test')]
test: pytest
[group('test')]
test-cov:
pytest {{test_dir}}/ --cov={{src_dir}}/{{package}} --cov-report=term-missing --cov-report=html
# =============================================================================
# CI / Quality
# =============================================================================
# Composite recipes that chain multiple checks.
# `ci` is the full pipeline; `check` is the fast subset (no tests).
[group('ci')]
ci: lint typecheck test
[group('ci')]
check: ruff mypy
# =============================================================================
# Docker Compose — Production (delete if no Docker)
# =============================================================================
# These wrap `docker compose` (compose.yml).
# Default params use `service='backend'` syntax — overridable at call site.
[group('docker')]
up *ARGS:
docker compose up {{ARGS}}
[group('docker')]
start *ARGS:
docker compose up -d {{ARGS}}
[group('docker')]
down *ARGS:
docker compose down {{ARGS}}
[group('docker')]
stop:
docker compose stop
[group('docker')]
build *ARGS:
docker compose build {{ARGS}}
[group('docker')]
rebuild:
docker compose build --no-cache
[group('docker')]
logs *SERVICE:
docker compose logs -f {{SERVICE}}
[group('docker')]
ps:
docker compose ps
[group('docker')]
shell service='backend':
docker compose exec -it {{service}} /bin/bash
# =============================================================================
# Docker Compose — Dev (delete if no Docker)
# =============================================================================
# Same commands but targeting dev.compose.yml.
[group('dev')]
dev-up *ARGS:
docker compose -f dev.compose.yml up {{ARGS}}
[group('dev')]
dev-start *ARGS:
docker compose -f dev.compose.yml up -d {{ARGS}}
[group('dev')]
dev-down *ARGS:
docker compose -f dev.compose.yml down {{ARGS}}
[group('dev')]
dev-stop:
docker compose -f dev.compose.yml stop
[group('dev')]
dev-build *ARGS:
docker compose -f dev.compose.yml build {{ARGS}}
[group('dev')]
dev-rebuild:
docker compose -f dev.compose.yml build --no-cache
[group('dev')]
dev-logs *SERVICE:
docker compose -f dev.compose.yml logs -f {{SERVICE}}
[group('dev')]
dev-ps:
docker compose -f dev.compose.yml ps
[group('dev')]
dev-shell service='backend':
docker compose -f dev.compose.yml exec -it {{service}} /bin/bash
# =============================================================================
# Database — Docker (delete if no database)
# =============================================================================
# Alembic migrations executed inside the running backend container.
[group('db')]
migrate *ARGS:
docker compose exec backend alembic upgrade {{ARGS}}
[group('db')]
migration message:
docker compose exec backend alembic revision --autogenerate -m "{{message}}"
[group('db')]
rollback:
docker compose exec backend alembic downgrade -1
[group('db')]
db-history:
docker compose exec backend alembic history --verbose
[group('db')]
db-current:
docker compose exec backend alembic current
# =============================================================================
# Database — Local (no Docker) (delete if no database)
# =============================================================================
[group('db-local')]
migrate-local *ARGS:
cd backend && uv run alembic upgrade {{ARGS}}
[group('db-local')]
migration-local message:
cd backend && uv run alembic revision --autogenerate -m "{{message}}"
[group('db-local')]
rollback-local:
cd backend && uv run alembic downgrade -1
[group('db-local')]
db-history-local:
cd backend && uv run alembic history --verbose
[group('db-local')]
db-current-local:
cd backend && uv run alembic current
# =============================================================================
# Setup
# =============================================================================
# First-time project bootstrap. For fullstack projects, chain sub-recipes.
[group('setup')]
setup:
@echo "Setting up development environment..."
uv sync --all-extras
@echo "Setup complete!"
# Fullstack alternative (uncomment and replace the simple setup above):
# [group('setup')]
# setup: setup-backend setup-frontend env
# @echo "Setup complete!"
#
# [group('setup')]
# setup-backend:
# @echo "Setting up backend..."
# cd backend && uv sync
# @echo "Backend ready!"
#
# [group('setup')]
# setup-frontend:
# @echo "Setting up frontend..."
# cd frontend && pnpm install
# @echo "Frontend ready!"
#
# [group('setup')]
# env:
# @if [ ! -f .env ]; then cp .env.example .env; echo "Created .env from .env.example"; fi
# @echo ".env ready — update with your values."
# =============================================================================
# Utilities
# =============================================================================
[group('util')]
info:
@echo "Project: {{project}}"
@echo "Version: {{version}}"
@echo "OS: {{os()}} ({{arch()}})"
# The `-` prefix ignores errors (e.g., dir doesn't exist). Keeps going.
[group('util')]
clean:
-rm -rf .mypy_cache
-rm -rf .pytest_cache
-rm -rf .ruff_cache
-rm -rf htmlcov
-rm -f .coverage
-rm -rf dist
-rm -rf build
@echo "Cache directories cleaned"
# [confirm(...)] prompts for Y/n before running — safety net for destructive ops.
[group('util')]
[confirm("Remove all build artifacts, caches, and virtual environment?")]
nuke:
@echo "Nuking everything..."
-rm -rf .mypy_cache .pytest_cache .ruff_cache htmlcov dist build
-rm -f .coverage
-rm -rf .venv
@echo "Nuke complete!"