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
20 changes: 20 additions & 0 deletions .github/scripts/check-uv-locks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Check that every project's uv.lock matches its pyproject.toml.
#
# The projects are the directories of the tracked pyproject.toml files (test
# fixtures excluded), so a new project is checked without editing this script
# or the workflow. Every project is checked before the script fails, so one run
# reports every stale lock. See docs/engineering/skills/dependencies.md.
set -euo pipefail

failed=0
while IFS= read -r pyproject; do
project="$(dirname "${pyproject}")"
echo "Checking ${project}/uv.lock"
if ! uv lock --check --project "${project}"; then
echo "::error file=${project}/uv.lock::uv.lock does not match pyproject.toml; run uv lock --project ${project}" >&2
failed=1
fi
done < <(git ls-files -- '*pyproject.toml' ':!:**/fixtures/**')

exit "${failed}"
2 changes: 1 addition & 1 deletion .github/scripts/modal-extract-versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ PROJECT_DIR="${1:-.}"

cd "$PROJECT_DIR"

uv run python -m src.modal.utils.extract_bundle_versions
uv run --frozen python -m src.modal.utils.extract_bundle_versions
8 changes: 4 additions & 4 deletions .github/scripts/modal-image-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fi
# PolicyEngine Core reads the HUGGING_FACE_TOKEN compatibility name in Modal.
(
cd "$REPO_ROOT/projects/policyengine-simulation-executor"
uv run modal secret create pe-uk-private-hf-read-token \
uv run --frozen modal secret create pe-uk-private-hf-read-token \
"HUGGING_FACE_TOKEN=$PE_UK_PRIVATE_HF_READ_TOKEN" \
--env="$MODAL_ENV" \
--force
Expand All @@ -30,20 +30,20 @@ fi
echo "=== Gateway image smoke (env: $MODAL_ENV) ==="
(
cd "$REPO_ROOT/projects/policyengine-simulation-gateway"
uv run modal run --env="$MODAL_ENV" \
uv run --frozen modal run --env="$MODAL_ENV" \
src/policyengine_simulation_gateway/smoke_app.py
)

echo "=== Executor image smoke (env: $MODAL_ENV) ==="
(
cd "$REPO_ROOT/projects/policyengine-simulation-executor"
uv run modal run --env="$MODAL_ENV" src/modal/smoke_app.py
uv run --frozen modal run --env="$MODAL_ENV" src/modal/smoke_app.py
)

echo "=== Stage 12 static runtime file smoke (env: $MODAL_ENV) ==="
(
cd "$REPO_ROOT/projects/policyengine-simulation-executor"
uv run modal run --env="$MODAL_ENV" \
uv run --frozen modal run --env="$MODAL_ENV" \
src/modal/v2_static_runtime_files_smoke.py
)

Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/modal-precompute.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if [ -z "${GITHUB_OUTPUT:-}" ]; then
exit 1
fi

RUN_COMMAND=(uv run modal run --env="$MODAL_ENV" src/modal/precompute_app.py)
RUN_COMMAND=(uv run --frozen modal run --env="$MODAL_ENV" src/modal/precompute_app.py)
if [[ "$FORCE" == "true" || "$FORCE" == "1" ]]; then
RUN_COMMAND+=(--force)
fi
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/modal-record-deployment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ if [ -z "${POLICYENGINE_ARTIFACT_BUCKET:-}" ]; then
fi

echo "Recording deployment marker for ${ENVIRONMENT} (manifest ${MANIFEST_DIGEST})"
uv run python -m src.modal.utils.record_deployment \
uv run --frozen python -m src.modal.utils.record_deployment \
--environment "$ENVIRONMENT" \
--manifest-digest "$MANIFEST_DIGEST"
2 changes: 1 addition & 1 deletion .github/scripts/modal-setup-environments.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
set -euo pipefail

# Create staging environment if it doesn't exist
uv run modal environment create staging 2>/dev/null || echo "staging environment already exists"
uv run --frozen modal environment create staging 2>/dev/null || echo "staging environment already exists"

# main environment exists by default
echo "Modal environments ready"
4 changes: 2 additions & 2 deletions .github/scripts/modal-sync-secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fi
# environment in both staging and production. Synchronize that exact resource
# during deployment and stop immediately if the update fails; runtime storage
# and observability error handling remain independent of this deployment step.
uv run modal secret create gcp-credentials \
uv run --frozen modal secret create gcp-credentials \
"GOOGLE_APPLICATION_CREDENTIALS_JSON=$GCP_CREDENTIALS_JSON" \
--env="main" \
--force
Expand All @@ -72,7 +72,7 @@ if [ -n "$NORMALIZED_ISSUER" ]; then
esac
fi

uv run modal secret create policyengine-gateway-auth \
uv run --frozen modal secret create policyengine-gateway-auth \
"GATEWAY_AUTH_ISSUER=$NORMALIZED_ISSUER" \
"GATEWAY_AUTH_AUDIENCE=${GATEWAY_AUTH_AUDIENCE:-}" \
"GATEWAY_AUTH_REQUIRED=${GATEWAY_AUTH_REQUIRED:-}" \
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/simulation-run-integ-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ fi

if [ "$ENVIRONMENT" = "beta" ]; then
echo "Running all simulation integration tests (including beta_only)"
uv run pytest tests/simulation/ -v
uv run --frozen pytest tests/simulation/ -v
else
echo "Running simulation integration tests (excluding beta_only)"
uv run pytest tests/simulation/ -v -m "not beta_only"
uv run --frozen pytest tests/simulation/ -v -m "not beta_only"
fi
2 changes: 1 addition & 1 deletion .github/scripts/stage12-cache-precompute.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ modal_environment="${1:?Modal environment is required}"

output_file="$(mktemp)"
trap 'rm -f "${output_file}"' EXIT
uv run modal run --env="${modal_environment}" src/modal/stage12_precompute_app.py 2>&1 | tee "${output_file}"
uv run --frozen modal run --env="${modal_environment}" src/modal/stage12_precompute_app.py 2>&1 | tee "${output_file}"
digest_line="$(tr -d '\r' <"${output_file}" | grep '^STAGE12_CACHE_MANIFEST_DIGEST=' | tail -n 1 || true)"
if [[ -z "${digest_line}" ]]; then
echo "Stage 12 precompute returned no cache manifest digest" >&2
Expand Down
4 changes: 2 additions & 2 deletions .github/scripts/stage12-sync-modal-secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ jq -n \
'{GOOGLE_APPLICATION_CREDENTIALS_JSON: $credentials}' \
>"${credentials_modal_file}"

uv run modal secret create stage12-evaluation-runtime \
uv run --frozen modal secret create stage12-evaluation-runtime \
--from-json "${runtime_modal_file}" \
--env "${modal_environment}" \
--force
uv run modal secret create stage12-evaluation-gcp-credentials \
uv run --frozen modal secret create stage12-evaluation-gcp-credentials \
--from-json "${credentials_modal_file}" \
--env "${modal_environment}" \
--force
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/stage12-v2-application-name.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

set -euo pipefail

name="$(uv run python -c 'from policyengine_simulation_contract.stage12_manifest import v2_application_name; from policyengine_simulation_executor.stage12_bundle import load_stage12_bundle; print(v2_application_name(load_stage12_bundle().bundle.policyengine_version))')"
name="$(uv run --frozen python -c 'from policyengine_simulation_contract.stage12_manifest import v2_application_name; from policyengine_simulation_executor.stage12_bundle import load_stage12_bundle; print(v2_application_name(load_stage12_bundle().bundle.policyengine_version))')"
echo "name=${name}" >> "$GITHUB_OUTPUT"
2 changes: 1 addition & 1 deletion .github/scripts/stage12-validate-infrastructure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ require_secret_accessor \
"${STAGE12_GCP_CREDENTIALS_SECRET_NAME}" \
"${STAGE12_DEPLOY_SERVICE_ACCOUNT}"

uv run --project projects/policyengine-simulation-entry \
uv run --frozen --project projects/policyengine-simulation-entry \
python -m policyengine_simulation_entry.stage12_infrastructure \
--database-url-file "${database_url_file}" \
--expected-role "${expected_role}" \
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/stage12-validate-v2-workers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MODAL_ENV="${1:?Modal environment required}"
CACHE_MANIFEST_SHA256="${2:?Stage 12 cache manifest digest required}"

output="${RUNNER_TEMP}/stage12-worker-validation.json"
uv run python -m src.modal.utils.validate_v2_worker_release \
uv run --frozen python -m src.modal.utils.validate_v2_worker_release \
--environment "${MODAL_ENV}" \
--cache-manifest-sha256 "${CACHE_MANIFEST_SHA256}" \
--output "${output}"
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/update-policyengine-package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ done
(
cd "$PROJECT_PATH"
uv lock --check
uv run --extra test pytest \
uv run --frozen --extra test pytest \
tests/test_bundle_version_export.py \
tests/test_policyengine_dependency_source.py \
tests/test_modal_bundle_image.py \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-image-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
working-directory: projects/policyengine-simulation-executor
env:
HUGGING_FACE_TOKEN: ${{ secrets.PE_UK_PRIVATE_HF_READ_TOKEN }}
run: uv run python -m src.modal.utils.validate_hf_access
run: uv run --frozen python -m src.modal.utils.validate_hf_access

- name: Run image smokes
env:
Expand Down
17 changes: 11 additions & 6 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ jobs:

- name: Install dependencies
working-directory: ${{ matrix.project }}
run: uv sync --extra test
run: uv sync --frozen --extra test

- name: Run tests
working-directory: ${{ matrix.project }}
run: uv run pytest tests/ -v
run: uv run --frozen pytest tests/ -v

lint:
name: Lint
Expand All @@ -97,10 +97,10 @@ jobs:
run: uv tool install ruff==0.15.22

- name: Run ruff format check
run: uv run ruff format --check projects/*/src libs/*/src
run: uv run --frozen ruff format --check projects/*/src libs/*/src

- name: Run ruff check
run: uv run ruff check .
run: uv run --frozen ruff check .

quality-guards:
name: Quality guards
Expand Down Expand Up @@ -228,17 +228,22 @@ jobs:
run: |
./scripts/generate-clients.sh

# After the clients exist: policyengine-apis-integ depends on the generated
# client by path, so its lock can only be checked once it is generated.
- name: Check every uv.lock matches its pyproject.toml
run: .github/scripts/check-uv-locks.sh

- name: Start services
run: .github/scripts/start-local-services.sh deployment/docker-compose.yml

- name: Install integration test dependencies
working-directory: projects/policyengine-apis-integ
run: uv sync --extra test
run: uv sync --frozen --extra test

- name: Run integration tests (local services only)
working-directory: projects/policyengine-apis-integ
# Run tests against local Docker services only (not Modal staging)
run: uv run pytest tests/ -v -m "not requires_gcp and not beta_only"
run: uv run --frozen pytest tests/ -v -m "not requires_gcp and not beta_only"

- name: Show service logs on failure
if: failure()
Expand Down
Loading
Loading