diff --git a/.github/workflows/ci-python-library-README.md b/.github/workflows/ci-python-library-README.md index 9771e38..ecf817f 100644 --- a/.github/workflows/ci-python-library-README.md +++ b/.github/workflows/ci-python-library-README.md @@ -7,6 +7,7 @@ This reusable workflow is part of the City of Helsinki's GitHub Actions setup, s - **Commit Linting**: Enforces commit message standards using [commitlint](https://commitlint.js.org/). - **Code Style Checks**: Verifies code style and formatting using [pre-commit](https://pre-commit.com/). - **Automated Testing**: Runs project tests across multiple Python versions using [hatch](https://hatch.pypa.io/). +- **Database Testing**: Optionally starts a PostgreSQL (with or without PostGIS) service and sets `DATABASE_URL` for tests that require a database. - **Code Quality Analysis**: Performs a [SonarQube Cloud](https://sonarcloud.io/) scan. ## Requirements for Projects Using the Workflow @@ -28,6 +29,8 @@ To use this reusable workflow, create a project-specific workflow file in your ` - **`python-version`** (string): Python version to use for pre-commit checks. Defaults to `"3.x"`. - **`enable-sonar`** (boolean): Whether to run the SonarQube Cloud Scan job after tests. Defaults to `true`. +- **`postgres-major-version`** (string): PostgreSQL major version to use for testing. Supported versions: `13`, `14`, `17`. Optional - omit if no database is needed. +- **`use-postgis`** (boolean): Set to `true` to use the PostGIS extension. Requires `postgres-major-version` to be set. Defaults to `false`. ### Secrets @@ -59,3 +62,32 @@ jobs: with: python-matrix: "['3.10', '3.11', '3.12', '3.13', '3.14']" ``` + +### Example usage with PostgreSQL (`/.github/workflows/ci.yml`) + +```yaml +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + common: + uses: City-of-Helsinki/.github/.github/workflows/ci-python-library.yml@main + secrets: + sonar-token: ${{ secrets.SONAR_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} + with: + python-matrix: "['3.12', '3.13']" + postgres-major-version: "17" +``` + +When `postgres-major-version` is set, the workflow starts a PostgreSQL service and exposes a `DATABASE_URL` environment variable (`postgres://test_user:test_password@localhost/test_db`) to the test runner. diff --git a/.github/workflows/ci-python-library.yml b/.github/workflows/ci-python-library.yml index adb8a8c..6836bf1 100644 --- a/.github/workflows/ci-python-library.yml +++ b/.github/workflows/ci-python-library.yml @@ -17,6 +17,16 @@ on: required: false type: boolean default: true + postgres-major-version: + description: "PostgreSQL major version to use for testing (supported: 13, 14, 17). Optional - omit if no database is needed." + required: false + type: string + default: '' + use-postgis: + description: "Set to true to use the PostGIS extension. Requires postgres-major-version to be set." + required: false + type: boolean + default: false secrets: sonar-token: description: "Token for SonarQube Cloud Scan. Required if enable-sonar is set to true." @@ -60,6 +70,52 @@ jobs: python_version: ${{ fromJSON(inputs.python-matrix) }} steps: + - name: Validate provided PostgreSQL major version + if: ${{ inputs.postgres-major-version != '' }} + env: + POSTGRES_MAJOR_VERSION: ${{ inputs.postgres-major-version }} + run: | + supported_versions=("13" "14" "17") + if [[ ! " ${supported_versions[*]} " == *" ${POSTGRES_MAJOR_VERSION} "* ]]; then + echo "Error: Unsupported PostgreSQL major version provided. Supported versions are 13, 14 and 17." + exit 1 + fi + + - name: Start PostgreSQL + if: ${{ inputs.postgres-major-version != '' }} + env: + # The workflow supports only the PostgreSQL and PostGIS versions used in Platta + POSTGRES_IMAGE: ${{ inputs.use-postgis && + (inputs.postgres-major-version == '17' && 'postgis/postgis:17-3.5-alpine' || + inputs.postgres-major-version == '14' && 'postgis/postgis:14-3.2-alpine' || + inputs.postgres-major-version == '13' && 'postgis/postgis:13-3.2-alpine') || + (inputs.postgres-major-version == '17' && 'postgres:17-alpine' || + inputs.postgres-major-version == '14' && 'postgres:14-alpine' || + inputs.postgres-major-version == '13' && 'postgres:13-alpine') }} + run: | + docker run -d --name postgres \ + -e POSTGRES_USER=test_user \ + -e POSTGRES_PASSWORD=test_password \ + -e POSTGRES_DB=test_db \ + -p 5432:5432 \ + --health-cmd pg_isready \ + --health-interval 10s \ + --health-timeout 5s \ + --health-retries 5 \ + "$POSTGRES_IMAGE" + echo "Waiting for PostgreSQL to become healthy..." + for _ in $(seq 1 30); do + status=$(docker inspect --format '{{.State.Health.Status}}' postgres) + if [[ "$status" == "healthy" ]]; then + echo "PostgreSQL is healthy." + exit 0 + fi + sleep 2 + done + echo "Error: PostgreSQL did not become healthy in time." + docker logs postgres + exit 1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Python ${{ matrix.python_version }} @@ -79,6 +135,22 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- + - name: Install system packages + if: ${{ inputs.postgres-major-version != '' }} + env: + USE_POSTGIS: ${{ inputs.use-postgis }} + run: | + packages=(libpq-dev) + if [[ "${USE_POSTGIS}" == "true" ]]; then + packages+=(gdal-bin) + fi + sudo apt-get update + sudo apt-get install -y "${packages[@]}" + + - name: Set database URL + if: ${{ inputs.postgres-major-version != '' }} + run: echo "DATABASE_URL=${{ inputs.use-postgis == true && 'postgis' || 'postgres' }}://test_user:test_password@localhost/test_db" >> $GITHUB_ENV + - name: Install hatch run: python -m pip install hatch