Skip to content

Commit

Permalink
Delegate PG installation to upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
nyurik committed May 26, 2024
1 parent e2ca408 commit 4db2df2
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 210 deletions.
94 changes: 4 additions & 90 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@
[![CI build](https://github.com/nyurik/action-setup-postgis/actions/workflows/ci.yml/badge.svg)](https://github.com/nyurik/action-setup-postgis/actions)
[![Marketplace](https://img.shields.io/badge/market-setup--postgis-6F42C1?logo=github)](https://github.com/marketplace/actions/setup-postgresql-and-postgis-for-linux-macos-windows)

This GitHub action sets up a PostgreSQL server with PostGIS extension. The code is based on
the [ikalnytskyi/action-setup-postgres](https://github.com/ikalnytskyi/action-setup-postgres) action.
> [!TIP]
>
> PostgreSQL installation is done by the `ikalnytskyi/action-setup-postgres` action. All parameters are passed as is to the original action, with the addition of the `cached-dir` parameter to specify where to download and cache PostGIS binaries. See the [original documentation](https://github.com/ikalnytskyi/action-setup-postgres) for more details.
* Runs on Linux, macOS and Windows GitHub runners.
* Adds PostgreSQL [binaries](https://www.postgresql.org/docs/current/reference-client.html) (e.g. `psql`) to `PATH`.
* Uses PostgreSQL installed in [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
* Runs on all Linux, macOS and Windows GitHub runners
* Installs the correct version of PostGIS and runs `CREATE EXTENSION postgis` in the new database.
* Linux version is installed from the [PostGIS apt repository](https://postgis.net/install/).
* Windows version is installed from the [OSGeo](https://download.osgeo.org/postgis/windows/).
* MacOS version is installed using [Homebrew package](https://formulae.brew.sh/formula/postgis).
* [Easy to check](action.yml) that IT DOES NOT contain malicious code.

See also [action-setup-nginx](https://github.com/nyurik/action-setup-nginx) to configure NGINX service.

Expand All @@ -31,19 +29,6 @@ steps:
CONNECTION_STR: ${{ steps.postgres.outputs.connection-uri }}
```
> [!IMPORTANT]
>
> In order to connect to a PostgreSQL server, use either connection parameters
> from the table below ([link](#outputs)), or retrieve a
> connection URI from the `connection-uri` output ([link](#advanced)).

> [!TIP]
>
> `libpq`-using applications may choose to set the `PGSERVICE=postgres`
> environment variable instead ([link](#create-a-new-user-w-database-via-cli)),
> where `postgres` is the service name extracted from the `service-name`
> output.

#### Input parameters
| Key | Value | Default |
Expand All @@ -68,77 +53,6 @@ steps:
| usesuper | true |
| usecreatedb | true |

#### Advanced

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
with:
username: ci
password: sw0rdfish
database: test
port: 34837
id: postgres
- name: Test PostGIS is installed
run: psql -v ON_ERROR_STOP=1 -c 'SELECT PostGIS_Full_Version();' "$CONNECTION_STR"
env:
CONNECTION_STR: ${{ steps.postgres.outputs.connection-uri }}
```

## Recipes

#### Create a new user w/ database via CLI

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
id: postgres
- run: |
createuser myuser
createdb --owner myuser mydatabase
psql -c "ALTER USER myuser WITH PASSWORD 'mypassword'"
env:
# This activates connection parameters for the superuser created by
# the action in the step above. It's mandatory to set this before using
# createuser/psql and other libpq-using applications.
#
# The service name is the same as the username (i.e. 'postgres') but
# it's recommended to use action's output to get the name in order to
# be forward compatible.
PGSERVICE: ${{ steps.postgres.outputs.service-name }}
shell: bash
```

#### Create a new user w/ database via psycopg

```yaml
steps:
- uses: nyurik/action-setup-postgis@v2
```

```python
import psycopg
# 'postgres' is the username here, but it's recommended to use the
# action's 'service-name' output parameter here.
connection = psycopg.connect("service=postgres")
# CREATE/DROP USER statements don't work within transactions, and with
# autocommit disabled transactions are created by psycopg automatically.
connection.autocommit = True
connection.execute(f"CREATE USER myuser WITH PASSWORD 'mypassword'")
connection.execute(f"CREATE DATABASE mydatabase WITH OWNER 'myuser'")
```

## Rationale

At the time of developing there were no GitHub Actions on the marketplace to
setup a PostgreSQL server on Linux, Windows and macOS action runners. Most
solutions suggest using Docker which is not available on macOS and Windows
runners.

## License

The scripts and documentation in this project are released under the
Expand Down
132 changes: 12 additions & 120 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ inputs:
default: "5432"
required: false
cached-dir:
# TODO: move to runner's temp dir, help wanted
description: Where should the temporary downloads be placed. Used to download and cache PostGIS binary.
default: "downloads"
required: false
outputs:
connection-uri:
description: The connection URI to connect to PostgreSQL.
value: ${{ steps.set-outputs.outputs.connection-uri }}
value: ${{ steps.pg.outputs.connection-uri }}
service-name:
description: The service name with connection parameters.
value: ${{ steps.set-outputs.outputs.service-name }}
value: ${{ steps.pg.outputs.service-name }}
runs:
using: composite
steps:
Expand Down Expand Up @@ -132,124 +133,15 @@ runs:
& pg_ctl restart -D "$env:PGDATA"
& pg_isready
- name: Prerequisites
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
echo "$(pg_config --bindir)" >> $GITHUB_PATH
elif [ "$RUNNER_OS" == "Windows" ]; then
echo "$PGBIN" >> $GITHUB_PATH
echo "PQ_LIB_DIR=$PGROOT\lib" >> $GITHUB_ENV
# The Windows runner has some PostgreSQL environment variables set
# that may confuse users since they may be irrelevant to the
# PostgreSQL server we're using.
for name in "PGROOT" "PGDATA" "PGBIN" "PGUSER" "PGPASSWORD"; do
echo "$name=" >> $GITHUB_ENV
done
elif [ "$RUNNER_OS" == "macOS" ]; then
case "$(sw_vers -productVersion)" in
13.*|14.*)
# Unfortunately, the macOS 13 runner image doesn't come w/
# pre-installed PostgreSQL server.
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_INSTALL_UPGRADE=1
brew install --skip-post-install postgresql@14
;;
esac
fi
shell: bash

- name: Setup and start PostgreSQL
run: |
export PGDATA="$RUNNER_TEMP/pgdata"
export PWFILE="$RUNNER_TEMP/pwfile"
DEFAULT_ENCODING="UTF-8"
DEFAULT_LOCALE="en_US.$DEFAULT_ENCODING"
# Unfortunately, Windows Server 2019 doesn't understand locale
# specified in the format defined by the POSIX standard, i.e.
# <language>_<country>.<encoding>. Therefore, we have to convert it
# into something it can swallow, i.e. <language>-<country>.
if [[ "$RUNNER_OS" == "Windows" && "$(wmic os get Caption)" == *"2019"* ]]; then
DEFAULT_LOCALE="${DEFAULT_LOCALE%%.*}"
DEFAULT_LOCALE="${DEFAULT_LOCALE//_/-}"
fi
# Unfortunately 'initdb' could only receive a password via file on disk
# or prompt to enter on. Prompting is not an option since we're running
# in non-interactive mode.
echo '${{ inputs.password }}' > $PWFILE
# There are couple of reasons why we need to create a new PostgreSQL
# database cluster. First and foremost, we have to create a superuser
# with provided credentials. Second, we want the PostgreSQL client
# applications [1] to be available for execution without
# run-from-another-user dances. Third, we want to make sure that
# settings are the same between operating systems and aren't changed by
# package vendors.
#
# [1] https://www.postgresql.org/docs/15/reference-client.html
initdb \
--username="${{ inputs.username }}" \
--pwfile="$PWFILE" \
--auth="scram-sha-256" \
--encoding="$DEFAULT_ENCODING" \
--locale="$DEFAULT_LOCALE" \
--no-instructions
# Do not create unix sockets since they are created by default in the
# directory we have no permissions to (owned by system postgres user).
echo "unix_socket_directories = ''" >> "$PGDATA/postgresql.conf"
echo "port = ${{ inputs.port }}" >> "$PGDATA/postgresql.conf"
pg_ctl start
# Save required connection parameters for created superuser to the
# connection service file [1]. This allows using these connection
# parameters by setting 'PGSERVICE' environment variable or by
# requesting them via connection string.
#
# HOST is required for Linux/macOS because these OS-es default to unix
# sockets but we turned them off.
#
# PORT, USER, PASSWORD and DBNAME are required because they could be
# parametrized via action input parameters.
#
# [1] https://www.postgresql.org/docs/15/libpq-pgservice.html
cat <<EOF > "$PGDATA/pg_service.conf"
[${{ inputs.username }}]
host=localhost
port=${{ inputs.port }}
user=${{ inputs.username }}
password=${{ inputs.password }}
dbname=${{ inputs.database }}
EOF
echo "PGSERVICEFILE=$PGDATA/pg_service.conf" >> $GITHUB_ENV
shell: bash

- name: Setup PostgreSQL database
run: |
# The 'postgres' database is a pre-created database meant for use by
# users, utilities and third party applications. There's no way to
# parametrize the name, so all we can do is to avoid creating a
# database if provided name is 'postgres'.
if [ "${{ inputs.database }}" != "postgres" ]; then
createdb -O "${{ inputs.username }}" "${{ inputs.database }}"
fi
env:
PGSERVICE: ${{ inputs.username }}
shell: bash

- name: Set action outputs
run: |
CONNECTION_URI="postgresql://${{ inputs.username }}:${{ inputs.password }}@localhost:${{ inputs.port }}/${{ inputs.database }}"
echo "connection-uri=$CONNECTION_URI" >> $GITHUB_OUTPUT
echo "service-name=${{ inputs.username }}" >> $GITHUB_OUTPUT
shell: bash
id: set-outputs
- name: Setup PostgreSQL for Linux/macOS/Windows
id: pg
uses: ikalnytskyi/action-setup-postgres@v6
with:
username: "${{ inputs.username }}"
password: "${{ inputs.password }}"
database: "${{ inputs.database }}"
port: "${{ inputs.port }}"

- name: Enable PostGIS extension
run: psql -v ON_ERROR_STOP=1 -c 'CREATE EXTENSION IF NOT EXISTS postgis;' '${{ steps.set-outputs.outputs.connection-uri }}'
run: psql -v ON_ERROR_STOP=1 -c 'CREATE EXTENSION IF NOT EXISTS postgis;' '${{ steps.pg.outputs.connection-uri }}'
shell: bash

0 comments on commit 4db2df2

Please sign in to comment.