diff --git a/.editorconfig b/.editorconfig index e49e180..896fb86 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,3 +12,6 @@ indent_size = 2 [*.py] indent_size = 4 + +[{Makefile,*.mk}] +indent_style = tab diff --git a/.gitignore b/.gitignore index 6efa075..efe34ea 100644 --- a/.gitignore +++ b/.gitignore @@ -167,7 +167,9 @@ cython_debug/ .ruff_cache .idea -# Specific project gitignore +# Makefile +make/local.mk + +# mpt-tool migrations/ .migrations-state.json -settings.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 53ef4cf..8c7dba7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,8 +28,8 @@ repos: - id: flake8 additional_dependencies: [ - Flake8-pyproject==1.2.*, - Flake8-AAA==0.17.*, + flake8-aaa==0.17.*, + flake8-pyproject==1.2.*, wemake-python-styleguide==1.5.*, ] diff --git a/Dockerfile b/Dockerfile index fe54f61..6df0f92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,17 +2,33 @@ FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS base WORKDIR /mpt_tool -COPY . ./ - RUN uv venv /opt/venv -ENV VIRTUAL_ENV=/opt/venv +ENV UV_PROJECT_ENVIRONMENT=/opt/venv ENV PATH=/opt/venv/bin:$PATH FROM base AS build -RUN uv sync --frozen --no-cache --all-groups --active +COPY . . + +RUN uv sync --frozen --no-cache --no-dev FROM build AS dev +RUN uv sync --frozen --no-cache --dev + +CMD ["bash"] + +FROM build AS prod + +RUN rm -rf tests/ + +RUN groupadd -r appuser && useradd -r -g appuser -m -d /home/appuser appuser && \ + mkdir -p /home/appuser/.cache/uv && \ + chown -R appuser:appuser /mpt_tool /opt/venv /home/appuser + +ENV UV_CACHE_DIR=/home/appuser/.cache/uv + +USER appuser + CMD ["bash"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..845f513 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +MK_FILES := $(sort $(wildcard make/*.mk)) +-include $(MK_FILES) + +.DEFAULT_GOAL := help +.PHONY: $(shell awk -F: '/^[a-zA-Z0-9_-]+:([^=]|$$)/ {print $$1}' $(MAKEFILE_LIST)) + +require = $(if $(value $(1)),,$(error Missing required variable: $(1). Example: make $(MAKECMDGOALS) $(1)=)) + +help: ## Show available commands + @echo "Available commands:" + @awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z0-9_-]+:.*##/ {printf " make %-22s %s\n", $$1, $$2}' $(MAKEFILE_LIST) diff --git a/README.md b/README.md index fdcde1f..57b3495 100644 --- a/README.md +++ b/README.md @@ -19,58 +19,80 @@ to manage both schema and data migrations across multiple backends, ensuring con - Docker and Docker Compose plugin (`docker compose` CLI) - `make` - [CodeRabbit CLI](https://www.coderabbit.ai/cli) (optional. Used for running review check locally) -- Copy .env.sample to .env + ### Make targets overview -Common development workflows are wrapped in the `makefile`: +Common development workflows are wrapped in the `Makefile`. Run `make help` to see the list of available commands. + +### How the Makefile works + +The project uses a modular Makefile structure that organizes commands into logical groups: + +- **Main Makefile** (`Makefile`): Entry point that automatically includes all `.mk` files from the `make/` directory +- **Modular includes** (`make/*.mk`): Commands are organized by category: + - `common.mk` - Core development commands (build, test, format, etc.) + - `repo.mk` - Repository management and dependency commands + - `migrations.mk` - Database migration commands (Only available in extension repositories) + - `external_tools.mk` - Integration with external tools + + +You can extend the Makefile with your own custom commands creating a `local.mk` file inside make folder. This file is +automatically ignored by git, so your personal commands won't affect other developers or appear in version control. + -- `make help` – list available commands -- `make bash` – start the app container and open a bash shell -- `make build` – build the application image for development -- `make check` – run code quality checks (ruff, flake8, lockfile check) -- `make check-all` – run checks and tests -- `make format` – apply formatting and import fixes -- `make down` – stop and remove containers -- `make review` – check the code in the cli by running CodeRabbit -- `make run` – run the CLI tool -- `make test` – run the test suite with pytest +### Setup -## Running CLI commands +Follow these steps to set up the development environment: + +#### 1. Clone the repository -Run the CLI tool: ```bash -make run +git clone +``` +```bash +cd mpt-tool +``` + +#### 2. Create environment configuration + +Copy the sample environment file and update it with your values: + +```bash +cp .env.sample .env ``` -## Running tests +Edit the `.env` file with your actual configuration values. See the [Configuration](#configuration) section for details on available variables. -Tests run inside Docker using the dev configuration. +#### 3. Build the Docker images -Run the full test suite: +Build the development environment: ```bash -make test +make build ``` -Pass additional arguments to pytest using the `args` variable: +This will create the Docker images with all required dependencies and the virtualenv. + +#### 4. Verify the setup + +Run the test suite to ensure everything is configured correctly: ```bash -make test args="-k test_cli -vv" -make test args="tests/test_cli.py" +make test ``` -## Pre-commit +You're now ready to start developing! See [Running the cli](#running-the-cli) for next steps. + -Checking migrations with pre-commit: +## Running the cli -Add this to your .pre-commit-config.yaml +Before running, ensure your `.env` file is populated. -```yaml -- repo: https://github.com/softwareone-platform/mpt-tool - rev: '' # Use the sha / tag you want to point at - hooks: - - id: check-migrations +Start the cli: + +```bash +make run ``` ## Developer utilities @@ -84,3 +106,18 @@ make check-all # run checks and tests make format # auto-format code and imports make review # check the code in the cli by running CodeRabbit ``` + +## Configuration + +The following environment variables are typically set in `.env`. Docker Compose reads them when using the Make targets described above. + +### Application + +| Environment Variable | Default | Example | Description | +|----------------------------------------|-------------------------|-------------------------------------------|-------------------------------------------------------------------------------------------| +| `MPT_API_BASE_URL` | `http://localhost:8000` | `https://portal.softwareone.com/mpt` | SoftwareONE Marketplace API URL | +| `MPT_API_TOKEN` | - | eyJhbGciOiJSUzI1N... | SoftwareONE Marketplace API Token | +| `MPT_TOOL_STORAGE_TYPE` | `local` | `airtable` | Storage type for MPT tools (local or airtable) | +| `MPT_TOOL_STORAGE_AIRTABLE_API_KEY` | - | patXXXXXXXXXXXXXX | Airtable API key for MPT tool storage (required when storage type is airtable) | +| `MPT_TOOL_STORAGE_AIRTABLE_BASE_ID` | - | appXXXXXXXXXXXXXX | Airtable base ID for MPT tool storage (required when storage type is airtable) | +| `MPT_TOOL_STORAGE_AIRTABLE_TABLE_NAME` | - | MigrationTracking | Airtable table name for MPT tool storage (required when storage type is airtable) | diff --git a/docs/PROJECT_DESCRIPTION.md b/docs/PROJECT_DESCRIPTION.md index e8ccee3..3f16809 100644 --- a/docs/PROJECT_DESCRIPTION.md +++ b/docs/PROJECT_DESCRIPTION.md @@ -340,6 +340,18 @@ Run `mpt-service-cli --help` to see all available commands and params: - Create a new migration with the updated logic - Never modify an already-applied migration in production +## Pre-commit + +Checking migrations with pre-commit: + +Add this to your .pre-commit-config.yaml + +```yaml +- repo: https://github.com/softwareone-platform/mpt-tool + rev: '' # Use the sha / tag you want to point at + hooks: + - id: check-migrations +``` ## Development diff --git a/make/common.mk b/make/common.mk new file mode 100644 index 0000000..b64a83d --- /dev/null +++ b/make/common.mk @@ -0,0 +1,43 @@ +DC = docker compose -f compose.yaml +RUN = $(DC) run --rm app +RUN_IT = $(DC) run --rm -it app + +bash: ## Open a bash shell + $(RUN_IT) bash + +build: ## Build images + $(DC) build + +check: ## Check code quality with ruff + $(RUN) bash -c "ruff format --check . && ruff check . && flake8 . && uv lock --check" + +check-all: check test ## Run checks and tests + +down: ## Stop and remove containers + $(DC) down + +format: ## Format code + $(RUN) bash -c "ruff check --select I --fix . && ruff format ." + +run: ## Run service + $(DC) up + +shell: ## Open Django shell + $(RUN_IT) bash -c "swoext shell" + +test: ## Run test + $(RUN) pytest $(if $(args),$(args),.) + +uv-add: ## Add a production dependency (pkg=) + $(call require,pkg) + $(RUN) bash -c "uv add $(pkg)" + $(MAKE) build + +uv-add-dev: ## Add a dev dependency (pkg=) + $(call require,pkg) + $(RUN) bash -c "uv add --dev $(pkg)" + $(MAKE) build + +uv-upgrade: ## Upgrade all packages or a specific package (use pkg="package_name" to target one) + $(RUN) bash -c "uv lock $(if $(pkg),--upgrade-package $(pkg),--upgrade) && uv sync" + $(MAKE) build diff --git a/make/external_tools.mk b/make/external_tools.mk new file mode 100644 index 0000000..f60ac1f --- /dev/null +++ b/make/external_tools.mk @@ -0,0 +1,2 @@ +review: ## Run CodeRabbit code review in interactive mode. Pass args= to override or include more options + coderabbit review $(args) diff --git a/make/repo.mk b/make/repo.mk new file mode 100644 index 0000000..e201827 --- /dev/null +++ b/make/repo.mk @@ -0,0 +1 @@ +## Add repo-specific targets here. Do not modify the shared *.mk files. diff --git a/makefile b/makefile deleted file mode 100644 index 3df4c12..0000000 --- a/makefile +++ /dev/null @@ -1,44 +0,0 @@ -.PHONY: bash build check check-all down format review run test help - -DC = docker compose -f compose.yaml - -help: - @echo "Available commands:" - @echo " make bash - Open a bash shell in the app container." - @echo " make build - Build images." - @echo " make check - Check code quality with ruff." - @echo " make check-all - Run checks and tests." - @echo " make down - Stop and remove containers." - @echo " make format - Format code." - @echo " make review - Check the code in the cli by running CodeRabbit." - @echo " make run - Open a shell with the CLI help and ready to run commands." - @echo " make test - Run tests." - @echo " make help - Display this help message." - -bash: - $(DC) run --rm -it app bash - -build: - $(DC) build - -check: - $(DC) run --rm app bash -c "ruff format --check . && ruff check . && flake8 . && mypy . && uv lock --check" - -check-all: - $(MAKE) check - $(MAKE) test - -down: - $(DC) down - -format: - $(DC) run --rm app bash -c "ruff check --select I --fix . && ruff format ." - -review: - coderabbit review --prompt-only - -run: - $(DC) run --rm -it app bash -c "mpt-service-cli migrate --help && exec bash" - -test: - $(DC) run --rm app pytest $(if $(args),$(args),.) diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index 199ea39..49d6db5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,7 @@ per-file-ignores = [ ] [tool.ruff] +# Ruff config: https://docs.astral.sh/ruff/settings preview = true target-version = "py312" output-format = "full" @@ -99,7 +100,6 @@ line-length = 100 [tool.ruff.format] quote-style = "double" -docstring-code-format = false [tool.ruff.lint] select = [