-
Notifications
You must be signed in to change notification settings - Fork 731
feat: integrate mailing list service (CM-1318) #4346
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
Merged
Changes from 11 commits
Commits
Show all changes
80 commits
Select commit
Hold shift + click to select a range
449f02b
chore: scaffold mailing_list_integration service (CM-1318)
themarolt 1c9c16c
feat: add mailinglist schema tables (CM-1318)
themarolt 1194e9c
feat: add mailing list database layer (CM-1318)
themarolt 2cbb25f
feat: port noteren email parser into service (CM-1318)
themarolt 93e5793
feat: add public-inbox mirror service (CM-1318)
themarolt 3da5d5c
feat: add kafka queue producer (CM-1318)
themarolt f250f68
feat: add mailing list poll worker and server (CM-1318)
themarolt 9fd947f
build: add mailing_list_integration dockerfile and wiring (CM-1318)
themarolt 7e086b0
chore: add mailing list dev seed and docs (CM-1318)
themarolt bfc56b6
fix: ruff CI-breaking lint errors and wrong activity type (CM-1318)
themarolt 212875a
chore: remove dead settings from mailing list integration (CM-1318)
themarolt f6b291c
fix: regenerate manifest after initial lore list clone (CM-1318)
themarolt 04136f0
fix: correct base image and container paths for mailing-list-integrat…
themarolt 1b9e96a
feat: add mailing list onboarding endpoint (CM-1318)
themarolt 037a969
fix: harden mailing list bug fixes and add activity type wiring (CM-1…
themarolt cf4735c
Merge branch 'main' into feat/mailing-list-integration-CM-1318
themarolt f521e7a
Merge remote-tracking branch 'origin/main' into feat/mailing-list-int…
themarolt 9985ca8
fix: address simple mailing list PR review comments (CM-1318)
themarolt d324ea1
fix: validate mailing list name to prevent path traversal (CM-1318)
themarolt 3cacf06
fix: honor stored sourceUrl for mirror clone and permalinks (CM-1318)
themarolt 28263ab
fix: skip unparseable commits instead of blocking list forever (CM-1318)
themarolt bfdcf1e
fix: reclaim stale locked mailing lists after crash (CM-1318)
themarolt 0e43d27
fix: flush activities and checkpoint heads in batches during onboardi…
themarolt 48c6de2
fix: make activity result inserts idempotent on retry (CM-1318)
themarolt 1d2fcb8
fix: await kafka delivery futures for actual broker ack (CM-1318)
themarolt 9a86494
fix: run read_email in a thread to avoid blocking event loop (CM-1318)
themarolt 6287b8c
fix: use longer timeout for initial public-inbox clone (CM-1318)
themarolt 435772b
fix: set score on mailing list message activities (CM-1318)
themarolt e993187
fix: avoid sourceId collision for messages without Message-ID (CM-1318)
themarolt 694d244
refactor: convert ListWorker class to plain functions (CM-1318)
themarolt 6461853
fix: soft-delete mailing lists removed from integration settings (CM-…
themarolt 997b0d6
fix: reject mailing list connect if already owned by another project …
themarolt fac52d3
fix: normalize case in member/objectMember username comparisons (CM-1…
themarolt 834aa40
fix: only strip first-line From: override, not later From: content (C…
themarolt b055aa7
fix: key mirror dir by list id, not user-supplied name (CM-1318)
themarolt d698cc9
fix: harden list-worker lock/checkpoint handling against races (CM-1318)
themarolt 8064547
fix: harden mailing list connect request validation (CM-1318)
themarolt 977d45e
fix: clear deletedAt when re-onboarding removed mailing list (CM-1318)
themarolt 2df8842
fix: avoid collapsing distinct authors with missing From header (CM-1…
themarolt 3a19d99
fix: emit compact JSONL from parse_id debug CLI (CM-1318)
themarolt 9eafca1
fix: gate mailing list onboarding on integration.results backlog (CM-…
themarolt d640e6e
docs: fix example list name in mailing list integration README (CM-1318)
themarolt 11332de
ci: run python lint/test on pyproject.toml/uv.lock changes too (CM-1318)
themarolt e46243a
fix: validate mailing list script input with shared zod schema (CM-1318)
themarolt 42406aa
fix: skip onboarding/reprocessing lists of disconnected integrations …
themarolt 12d147c
fix: canonicalize mailing list sourceUrl trailing slash (CM-1318)
themarolt 1ee0dc9
fix: prevent concurrent mailing list connects from racing ownership (…
themarolt 2c49057
fix: allow reconnect after integration disconnect (CM-1318)
themarolt 05ac034
fix: reset processing state when reactivating soft-deleted mailing li…
themarolt caa9fc6
docs: clarify upsertMailingLists reactivation behavior (CM-1318)
themarolt d2a6465
fix: reject loopback/localhost mailing list sourceUrl (CM-1318)
themarolt 71b7f96
perf: bound integration.results scan in can_onboard_more (CM-1318)
themarolt 6262729
fix: clone lore mirror to temp dir, atomic rename on success (CM-1318)
themarolt 929bdfc
fix: throw on empty lists in mailingListConnectOrUpdate (CM-1318)
themarolt c0c2b06
fix: percent-encode message-id in built activity url (CM-1318)
themarolt 629c688
fix: annotate get_body's optional return type (CM-1318)
themarolt 0268e9d
fix: don't checkpoint shard head past a transient git-read failure (C…
themarolt 10f71da
fix: retry update_processed_heads on transient failure (CM-1318)
themarolt cfce316
fix: sync identities and segment on conflict-redirect owner attach (C…
themarolt 2eeeec4
fix: retry missing identities on per-member constraint conflict (CM-1…
themarolt 8698810
fix: soft-delete mailing lists when their integration is destroyed (C…
themarolt ec0ae0c
fix: set result-level segmentId so activities route to the correct li…
themarolt a3b8bc2
fix: canonicalize sourceUrl scheme/host case, default port, credentia…
themarolt c93b9fc
fix: persist LORE_MIRROR_DIR across container recreation (CM-1318)
themarolt e881aa9
fix: relax mailing-list name validation, mirror keys by list id not n…
themarolt db4b062
fix: don't fast-path create-conflict when identities resolve to multi…
themarolt 736dbe2
fix: use result() not selectNone() for advisory lock query (CM-1318)
themarolt b23b108
fix: initialize Exception.args from error_message on CrowdMailError (…
themarolt f970b07
fix: mark list FAILED not COMPLETED after unretried shard read error …
themarolt de6a08c
fix: promote matching identity to verified before early-return (CM-1318)
themarolt 19018a8
fix: use payload integrationId and promote verified identities on att…
themarolt 6797104
fix: await cancelled worker task so shutdown finally runs (CM-1318)
themarolt 53d8e80
fix: don't merge on ambiguous multi-owner identity conflict (CM-1318)
themarolt d952d18
chore: drop data_sink_worker fixes, split to separate branch (CM-1318)
themarolt a4bcebf
Merge remote-tracking branch 'origin/main' into feat/mailing-list-int…
themarolt d8e0d28
style: prettier format ADR files after merge (CM-1318)
themarolt a2ac5b9
style: fix prettier formatting in en.ts (CM-1318)
themarolt bd7e116
Merge remote-tracking branch 'origin/main' into feat/mailing-list-int…
themarolt 2fbabc4
Merge remote-tracking branch 'origin/main' into feat/mailing-list-int…
themarolt 5bcf617
Merge remote-tracking branch 'origin/main' into feat/mailing-list-int…
themarolt 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
50 changes: 50 additions & 0 deletions
50
backend/src/database/migrations/V1784048135__mailinglist-schema.sql
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,50 @@ | ||
| -- Create the mailinglist schema | ||
| CREATE SCHEMA IF NOT EXISTS mailinglist; | ||
|
|
||
| -- Mailing lists (lore/public-inbox lists onboarded into CDP) | ||
| CREATE TABLE mailinglist.lists ( | ||
| id UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), | ||
| "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), | ||
| "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), | ||
| "deletedAt" TIMESTAMP WITH TIME ZONE, | ||
|
|
||
| name TEXT NOT NULL, | ||
| "sourceUrl" TEXT NOT NULL, | ||
|
|
||
| "segmentId" UUID NOT NULL REFERENCES segments (id), | ||
| "integrationId" UUID NOT NULL REFERENCES public."integrations" (id), | ||
|
themarolt marked this conversation as resolved.
|
||
|
|
||
| UNIQUE ("sourceUrl") | ||
|
themarolt marked this conversation as resolved.
|
||
| ); | ||
|
|
||
| -- Per-list processing state (public-inbox shard head tracking) | ||
| CREATE TABLE mailinglist."listProcessing" ( | ||
| "listId" UUID PRIMARY KEY NOT NULL REFERENCES mailinglist.lists (id) ON DELETE CASCADE, | ||
|
|
||
| "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), | ||
| "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), | ||
|
|
||
| state VARCHAR(50) NOT NULL, | ||
| priority INTEGER NOT NULL DEFAULT 2, -- 0=urgent, 1=high, 2=normal | ||
|
|
||
| "lockedAt" TIMESTAMP WITH TIME ZONE, | ||
| "lastProcessedAt" TIMESTAMP WITH TIME ZONE, | ||
| "lastProcessedHeads" JSONB NOT NULL DEFAULT '{}' | ||
| ); | ||
|
|
||
| -- Indexes for optimal query performance | ||
|
|
||
| CREATE INDEX "ix_mailinglist_lists_segmentId" ON mailinglist.lists ("segmentId"); | ||
| CREATE INDEX "ix_mailinglist_lists_integrationId" ON mailinglist.lists ("integrationId"); | ||
|
|
||
| CREATE INDEX "ix_mailinglist_listProcessing_state" ON mailinglist."listProcessing" (state); | ||
| CREATE INDEX "ix_mailinglist_listProcessing_state_priority" ON mailinglist."listProcessing" (state, priority); | ||
|
|
||
| -- Comments for documentation | ||
| COMMENT ON SCHEMA mailinglist IS 'Schema for mailing list integration system that manages mailing list processing state'; | ||
| COMMENT ON TABLE mailinglist.lists IS 'Stores onboarded mailing lists (public-inbox/lore) and their segment/integration associations'; | ||
| COMMENT ON TABLE mailinglist."listProcessing" IS 'Per-list processing state including public-inbox shard head tracking'; | ||
|
|
||
| COMMENT ON COLUMN mailinglist."listProcessing".priority IS 'Processing priority: 0=urgent, 1=high, 2=normal'; | ||
| COMMENT ON COLUMN mailinglist."listProcessing".state IS 'Current processing state of the list'; | ||
| COMMENT ON COLUMN mailinglist."listProcessing"."lastProcessedHeads" IS 'JSONB map of shard index to last processed commit SHA, e.g. {"0": sha, "1": sha}'; | ||
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,4 @@ | ||
| DOCKERFILE="./services/docker/Dockerfile.mailing_list_integration" | ||
| CONTEXT="../" | ||
| REPO="sjc.ocir.io/axbydjxa5zuh/mailing-list-integration" | ||
| SERVICES="mailing-list-integration" |
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
69 changes: 69 additions & 0 deletions
69
scripts/services/docker/Dockerfile.mailing_list_integration
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,69 @@ | ||
| # Base image for both stages | ||
| FROM python:3.13.5-slim-bullseye AS base | ||
|
|
||
| # Builder stage: install build dependencies, uv, and dependencies | ||
| FROM base AS builder | ||
|
|
||
| # Install build dependencies | ||
| RUN apt-get update && apt-get install -y \ | ||
| build-essential \ | ||
| --no-install-recommends \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Copy uv binary from official image | ||
| COPY --from=ghcr.io/astral-sh/uv:0.7.17 /uv /usr/local/bin/uv | ||
|
|
||
| WORKDIR /usr/crowd/app | ||
|
|
||
| ENV UV_LINK_MODE=copy \ | ||
| UV_COMPILE_BYTECODE=1 \ | ||
| UV_PYTHON_DOWNLOADS=never \ | ||
| UV_PYTHON=python3.13 \ | ||
| UV_PROJECT_ENVIRONMENT=/usr/crowd/app/.venv \ | ||
| UV_VENV_PATH=/usr/crowd/app/.venv | ||
|
|
||
| # Copy only lock, pyproject.toml and License for dependency install caching | ||
| COPY ./services/apps/mailing_list_integration/pyproject.toml ./services/apps/mailing_list_integration/uv.lock ./LICENSE ./ | ||
|
|
||
| # Install dependencies excluding the project itself for better caching | ||
| RUN --mount=type=cache,target=/root/.cache/uv \ | ||
| uv sync --frozen --no-install-project --no-dev | ||
|
|
||
| # Copy full source code | ||
| COPY ./services/apps/mailing_list_integration ./LICENSE ./ | ||
|
|
||
| # Sync full project including the project itself | ||
| RUN --mount=type=cache,target=/root/.cache/uv \ | ||
| uv sync --frozen --no-dev | ||
|
|
||
|
|
||
| # Runner: minimal image with runtime deps and virtualenv only | ||
| FROM base AS runner | ||
|
|
||
| # Install runtime dependencies, including public-inbox for mirroring lists | ||
| RUN apt-get update && apt-get install -y \ | ||
| ca-certificates \ | ||
| git \ | ||
| public-inbox \ | ||
|
themarolt marked this conversation as resolved.
|
||
| --no-install-recommends \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| ENV PYTHONUNBUFFERED=1 \ | ||
| PYTHONDONTWRITEBYTECODE=1 \ | ||
| PIP_NO_CACHE_DIR=off | ||
|
|
||
| WORKDIR /usr/crowd/app | ||
|
|
||
| # Copy virtual environment and app source from builder | ||
| COPY --from=builder /usr/crowd/app/.venv /usr/crowd/app/.venv | ||
| COPY --from=builder /usr/crowd/app /usr/crowd/app | ||
|
|
||
| # Add virtual environment bin to PATH | ||
| ENV PATH="/usr/crowd/app/.venv/bin:$PATH" | ||
|
|
||
| # Make runner script executable | ||
| RUN chmod +x ./src/runner.sh | ||
|
|
||
| EXPOSE 8085 | ||
|
|
||
| CMD ["./src/runner.sh"] | ||
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,50 @@ | ||
|
|
||
| x-env-args: &env-args | ||
| DOCKER_BUILDKIT: 1 | ||
| NODE_ENV: docker | ||
| SERVICE: mailing-list-integration | ||
| SHELL: /bin/sh | ||
|
|
||
| services: | ||
| mailing-list-integration: | ||
| build: | ||
| context: ../../ | ||
| dockerfile: ./scripts/services/docker/Dockerfile.mailing_list_integration | ||
| working_dir: /usr/crowd/app/services/apps/mailing_list_integration | ||
|
Copilot marked this conversation as resolved.
Outdated
|
||
| env_file: | ||
| - ../../backend/.env.dist.local | ||
| - ../../backend/.env.dist.composed | ||
| - ../../backend/.env.override.local | ||
| - ../../backend/.env.override.composed | ||
| environment: | ||
| <<: *env-args | ||
| restart: always | ||
| networks: | ||
| - crowd-bridge | ||
| ports: | ||
| - '8086:8085' | ||
|
themarolt marked this conversation as resolved.
|
||
|
|
||
| mailing-list-integration-dev: | ||
| build: | ||
| context: ../../ | ||
| dockerfile: ./scripts/services/docker/Dockerfile.mailing_list_integration | ||
| command: ["./src/runner.sh", "local"] | ||
| working_dir: /usr/crowd/app/services/apps/mailing_list_integration | ||
| env_file: | ||
| - ../../backend/.env.dist.local | ||
| - ../../backend/.env.dist.composed | ||
| - ../../backend/.env.override.local | ||
| - ../../backend/.env.override.composed | ||
| environment: | ||
| <<: *env-args | ||
| hostname: mailing-list-integration | ||
| ports: | ||
| - '8086:8085' | ||
| networks: | ||
| - crowd-bridge | ||
| volumes: | ||
| - ../../services/apps/mailing_list_integration/src:/usr/crowd/app/services/apps/mailing_list_integration/src | ||
|
|
||
| networks: | ||
| crowd-bridge: | ||
| external: true | ||
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 @@ | ||
| ../../../LICENSE |
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,116 @@ | ||
| .DEFAULT_GOAL := help | ||
|
|
||
| help: ## Shows this help message | ||
| @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m %s\033[0m\n\n", substr($$0, 5) } ' $(MAKEFILE_LIST) | ||
|
|
||
| ifeq (cmd,$(firstword $(MAKECMDGOALS))) | ||
| CMD_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) | ||
| $(eval $(CMD_ARGS):;@:) | ||
| endif | ||
|
|
||
| COMPOSE_FILE = docker-compose -f ../../../scripts/services/mailing-list-integration.yaml | ||
|
|
||
| # Check if local setup is complete | ||
| check_setup: | ||
| @if ! command -v uv >/dev/null 2>&1; then \ | ||
| echo "❌ uv not found. Run 'make setup' first."; \ | ||
| exit 1; \ | ||
| fi | ||
| @if ! uv run ruff --version >/dev/null 2>&1; then \ | ||
| echo "📦 Installing dev dependencies..."; \ | ||
| uv sync --group dev; \ | ||
| fi | ||
|
|
||
| ##@ 🚀 Setup and installation | ||
|
|
||
| setup: ## Install uv and dev dependencies (only if not already installed) | ||
| @echo "🔧 Checking if uv is installed..." | ||
| @if command -v uv >/dev/null 2>&1; then \ | ||
| echo "✅ uv is already installed at $$(which uv)"; \ | ||
| echo "📦 Installing dev dependencies..."; \ | ||
| uv sync --group dev; \ | ||
| echo "✅ Setup complete"; \ | ||
| else \ | ||
| echo "📦 uv is required to:"; \ | ||
| echo " - Add/remove packages to pyproject.toml"; \ | ||
| echo " - Manage dependency versions and conflicts"; \ | ||
| echo " - Generate uv.lock for reproducible builds"; \ | ||
| echo " - Install dependencies locally for development"; \ | ||
| echo ""; \ | ||
| echo "Installing uv..."; \ | ||
| curl -LsSf https://astral.sh/uv/install.sh | sh; \ | ||
| echo "Adding uv to PATH..."; \ | ||
| echo 'export PATH="$$HOME/.cargo/bin:$$PATH"' >> ~/.zshrc; \ | ||
| echo 'export PATH="$$HOME/.cargo/bin:$$PATH"' >> ~/.bash_profile; \ | ||
| echo 'export PATH="$$HOME/.cargo/bin:$$PATH"' >> ~/.bashrc; \ | ||
| export PATH="$$HOME/.cargo/bin:$$PATH"; \ | ||
| echo "📦 Installing dev dependencies..."; \ | ||
| uv sync --group dev; \ | ||
| echo "✅ uv installed and dev dependencies ready"; \ | ||
| echo "📝 Next steps:"; \ | ||
| echo " - Restart your terminal or run: source ~/.zshrc"; \ | ||
| echo " - Use: make add_package name=<package> to add dependencies"; \ | ||
| fi | ||
|
|
||
| ##@ 🛠️ Local development tools | ||
|
|
||
| run: ## Start the mailing-list-integration service in interactive mode | ||
| $(COMPOSE_FILE) run --service-ports --rm mailing-list-integration-dev | ||
|
|
||
| cmd: ## Run any command inside the container, example: make cmd -- ls -la | ||
| $(COMPOSE_FILE) run --rm --no-deps mailing-list-integration-dev $(CMD_ARGS) | ||
|
|
||
| lint: check_setup ## Check code with ruff | ||
| @uv run ruff check src/ | ||
|
|
||
| format: check_setup ## Format code with ruff | ||
| @uv run ruff check --fix --select I src/ | ||
| @uv run ruff format src/ | ||
| $(MAKE) lint | ||
|
|
||
| fix-all: check_setup ## Fix all lint issues, format everything, and run final lint check | ||
| @echo "🔧 Fixing all linting issues..." | ||
| @uv run ruff check --fix src/ | ||
| @echo "✨ Formatting all code..." | ||
| @uv run ruff format src/ | ||
| @echo "🔍 Running final lint check..." | ||
| @uv run ruff check src/ | ||
| @echo "✅ All done! Code is linted and formatted." | ||
|
|
||
| rebuild: ## Rebuild the container | ||
| $(COMPOSE_FILE) build mailing-list-integration-dev | ||
| @echo "✅ Container rebuilt" | ||
|
|
||
| ##@ 📦 Dependency management | ||
|
|
||
| add_package: check_setup ## Add new package to pyproject.toml, example: make add_package name=requests | ||
| @echo "Adding $(name) to dependencies..." | ||
| @uv add $(name) | ||
| @echo "Rebuilding container..." | ||
| $(COMPOSE_FILE) build mailing-list-integration-dev | ||
| @echo "✅ Package $(name) added and container rebuilt" | ||
|
|
||
| remove_package: check_setup ## Remove package from pyproject.toml, example: make remove_package name=requests | ||
| @echo "Removing $(name) from dependencies..." | ||
| @uv remove $(name) | ||
| @echo "Rebuilding container..." | ||
| $(COMPOSE_FILE) build mailing-list-integration-dev | ||
| @echo "✅ Package $(name) removed and container rebuilt" | ||
|
|
||
| update_deps: check_setup ## Update all dependencies | ||
| @echo "Updating dependencies..." | ||
| @uv lock | ||
| @echo "Rebuilding container..." | ||
| $(COMPOSE_FILE) build mailing-list-integration-dev | ||
| @echo "✅ Dependencies updated and container rebuilt" | ||
|
|
||
| lock_deps: check_setup ## Generate/update uv.lock file | ||
| @echo "Generating uv.lock file..." | ||
| @uv lock | ||
| @echo "✅ uv.lock updated" | ||
|
|
||
| ##@ 🧪 Testing | ||
|
|
||
| test: check_setup ## Run tests | ||
| @echo "🧪 Running tests..." | ||
| @uv run pytest src/test/ -v |
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.